线程不安全的原因是什么,怎样解决?
这篇文章我们来了解为什么说线程不安全的原因,下文介绍了SimpleDateFormat线程安全测试及线程安全解决方法,下文有详细的介绍,有需要的朋友可以参考,接下来就跟随小编来一起学习一下吧!
本教程操作环境:windows7系统、java8版、DELL G3电脑。
线程不安全验证:
/**
* SimpleDateFormat线程安全测试
* 〈功能详细描述〉
*
* @author 17090889
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class SimpleDateFormatTest {
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue>
(1000), new MyThreadFactory("SimpleDateFormatTest"));
public void test() {
while (true) {
poolExecutor.execute(new Runnable() {
@Override
public void run() {
String dateString = simpleDateFormat.format(new Date());
try {
Date parseDate = simpleDateFormat.parse(dateString);
String dateString2 = simpleDateFormat.format(parseDate);
System.out.println(dateString.equals(dateString2));
}
catch (ParseException e) {
e.printStackTrace();
}
}
}
);
}
}
输出:
true false true true false
出现了false,说明线程不安全
1、format方法
public StringBuffer format(Date date, StringBuffer toAppendTo,
FieldPosition pos)
{
pos.beginIndex = pos.endIndex = 0;
return format(date, toAppendTo, pos.getFieldDelegate());
}
// Called from Format after creating a FieldDelegate
private StringBuffer format(Date date, StringBuffer toAppendTo,
FieldDelegate delegate) {
// Convert input date to time field list
calendar.setTime(date);
boolean useDateFormatSymbols = useDateFormatSymbols();
for (int i = 0;
i compiledPattern.length;
) {
int tag = compiledPattern[i] >
>
>
8;
int count = compiledPattern[i++] &
0xff;
if (count == 255) {
count = compiledPattern[i++] 16;
count |= compiledPattern[i++];
}
switch (tag) {
case TAG_QUOTE_ASCII_CHAR:
toAppendTo.append((char)count);
break;
case TAG_QUOTE_CHARS:
toAppendTo.append(compiledPattern, i, count);
i += count;
break;
default:
subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
break;
}
}
return toAppendTo;
}
protected Calendar calendar;
可以看到,多个线程之间共享变量calendar,并修改calendar。因此在多线程环境下,当多个线程同时使用相同的SimpleDateFormat对象(如static修饰)的话,如调用format方法时,多个线程会同时调用calender.setTime方法,导致time被别的线程修改,因此线程是不安全的。
此外,parse方法也是线程不安全的,parse方法实际调用的是CalenderBuilder的establish来进行解析,其方法中主要步骤不是原子操作。
解决方案:
1、将SimpleDateFormat定义成局部变量
2、 加一把线程同步锁:synchronized(lock)
3、使用ThreadLocal,每个线程都拥有自己的SimpleDateFormat对象副本。如:
/**
* SimpleDateFormat线程安全测试
* 〈功能详细描述〉
*
* @author 17090889
* @see [相关类/方法](可选)
* @since [产品/模块版本] (可选)
*/
public class SimpleDateFormatTest {
private static final ThreadLocalSimpleDateFormat>
THREAD_LOCAL = new ThreadLocalSimpleDateFormat>
() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
}
;
// private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue>
(1000), new MyThreadFactory("SimpleDateFormatTest"));
public void test() {
while (true) {
poolExecutor.execute(new Runnable() {
@Override
public void run() {
SimpleDateFormat simpleDateFormat = THREAD_LOCAL.get();
if (simpleDateFormat == null) {
simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
String dateString = simpleDateFormat.format(new Date());
try {
Date parseDate = simpleDateFormat.parse(dateString);
String dateString2 = simpleDateFormat.format(parseDate);
System.out.println(dateString.equals(dateString2));
}
catch (ParseException e) {
e.printStackTrace();
}
finally {
local.remove();
}
}
}
);
}
}
}
4、使用DateTimeFormatter代替SimpleDateFormat
DateTimeFormatter是线程安全的,默认提供了很多格式化方法,也可以通过ofPattern方法创建自定义格式化方法。
(1)格式化日期示例:
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
// 2019-11-20T15:04:29.017
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
String strDate=localDateTime.format(dtf);
System.out.println(strDate);
// 2019/23/20 15:23:46(2)解析日期
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
LocalDateTime localDateTime=LocalDateTime.parse("2019/11/20 15:23:46",dtf);
System.out.println(localDateTime);
// 2019-11-20T15:23:46现在对于为什么说线程不安全大家应该都清楚了吧,希望大家阅读完这篇文章能有所收获。最后,想要了解更多Java线程的相关内容,大家可以关注网络其它相关文章。
文本转载自PHP中文网
声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!
若转载请注明出处: 线程不安全的原因是什么,怎样解决?
本文地址: https://pptw.com/jishu/655120.html
