原创
SimpleDateFormat的线程安全问题
温馨提示:
本文最后更新于 2020年12月24日,已超过 1,429 天没有更新。若文章内的图片失效(无法正常加载),请留言反馈或直接联系我。
异常描述
// 如果没有加锁,没有去保证线程安全的话,那这个就是错误的写法,是线程不安全的
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
错误示例:
package com.lzhpo.common.config;
import org.junit.jupiter.api.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
/**
* @author Zhaopo Liu
*/
class DateFormatConfigTest {
private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* SimpleDateFormat线程不安全,没有保证线程安全的情况下,禁止使用全局SimpleDateFormat
* <pre>
* private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
* </pre>
*/
@Test
void testParse() {
for (int i = 0; i < 20; ++i) {
Thread thread = new Thread(() -> {
try {
// 错误
System.out.println(SIMPLE_DATE_FORMAT.parse("2020-06-01 11:35:00"));
// 正确
// System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2020-06-01 11:35:00"));
} catch (ParseException e) {
e.printStackTrace();
}
});
thread.start();
}
}
}
报错:
异常分析
从代码中可以看到:SimpleDateFormat继承DateFormat类,在SimpleDateFormat转换日期是通过Calendar对象来操作的,DateFormat类中维护一个Calendar对象,Calendar对象会被用来进行日期-时间计算,既被用于format方法也被用于parse方法。
那就追一下calendar
对象:
来到了CalendarBuilder
的establish
方法:
看一下clear
方法,可以发现它并不是线程安全的,如果此时,a线程将calendar
清空了,calendar
就没有新值了,恰好此时b线程刚好进入到parse
方法用到了calendar
对象,那就会产生线程安全问题了!
解决办法
方法1
不使用静态变量SimpleDateFormat
,使用局部变量SimpleDateFormat
,每次都new一个。
方法2
synchronized
等等…保证线程安全的情况下使用静态变量SimpleDateFormat
。
方法3
使用ThreadLocal.withInitial
/**
* 创建线程局部变量SimpleDateFormat
*/
private static final ThreadLocal<DateFormat> SAFE_FORMAT =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
@Test
void testSafe() {
for (int i = 0; i < 20; ++i) {
Thread thread = new Thread(() -> {
try {
System.out.println(SAFE_FORMAT.get().parse("2020-06-01 11:35:00"));
} catch (ParseException e) {
e.printStackTrace();
}
});
thread.start();
}
}
- 本文标签: SpringBoot Java Spring
- 本文链接: http://www.lzhpo.com/article/166
- 版权声明: 本文由lzhpo原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权