引言
日常开发中,我们经常需要使用时间相关类,说到时间相关类,想必大家对SimpleDateFormat并不陌生。主要是用它进行时间的格式化输出和解析,挺方便快捷的,但是SimpleDateFormat并不是一个线程安全的类。在多线程情况下,会出现异常,想必有经验的小伙伴也遇到过。下面我们就来分析分析SimpleDateFormat为什么不安全?是怎么引发的?以及多线程下有那些SimpleDateFormat的解决方案?
先看看《阿里巴巴开发手册》对于SimpleDateFormat是怎么看待的:
【强制】SimpleDateFormat是线程不安全的类,一般不要定义为static变量,如果定义为static变量,一定要加锁,或者是有DateUtils工具类。
正例:注意线程安全,使用DateUtils。亦推荐如下处理:
private static final ThreadLocal\<DateFormat\> df = new ThreadLocal\<DateFormat\>(){
@Override
protected DateFormat initialValue(){
return new SimpleDateFormat("yyyy-MM-dd");
}
}
说明:如果是JDK8的话,可以使用Instant代替Date,LocalDateTime代替Calender,DateTimeFormatter代替SimpleDateFormat,官方给出的解释是:simple beautiful strong immutable thread-safe。
1. 问题场景复现
一般我们使用SimpleDateFormat的时候会把它定义为一个静态变量,避免频繁创建它的对象实例,如下代码:
public class SimpleDateFormatTest {
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static String formatDate(Date date) throws ParseException {
return sdf.format(date);
}
public static Date parse(String strDate) throws ParseException {
return sdf.parse(strDate);
}
public static void main(String[] args) throws InterruptedException, ParseException {
System.out.println(sdf.format(new Date()));
}
}
是不是感觉没什么毛病?单线程下自然没毛病了,都是运用到多线程下就有大问题了。
测试下:
public static void main(String[] args) throws InterruptedException, ParseException {
ExecutorService service = Executors.newFixedThreadPool(100)