回答
SimpleDateFormat
不是线程安全,当多个线程使用一个 SimpleDateFormat
实例(如static修饰),调用 format()
格式化时,会出现线程不安全的情况。
其原因是 SimpleDateFormat
内部使用一个 Calendar
实例来存储解析和格式化的中间结果,但这个 Calendar
实例是一个成员变量且可变,当多个线程共享 SimpleDateFormat
时,也会共享 Calendar
,然而 SimpleDateFormat
内部没有进行任何形式的锁或者同步机制来保护这个 Calendar
,所以,在多线程环境下,他们之间就会互相干扰,导致日期解析或格式化错误。
详细分析
SimpleDateFormat 线程不安全演示
- 示例一
@Test
public void test01() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
while (true){
new Thread(() -> {
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();
}
}).start();
}
}
如果是线程安全的,那么结果输出一定全是 true,然后事实结果如下:
有报错的,有为 false,所以肯定不是线程安全的。
- 示例二
@Test
public void test02() throws InterruptedException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str1 = "2024-01-25 11:12:13";
String str2 = "2024-01-26 22:23:24";
while (true) {
new Thread(() -> {
try {
System.out.println(str1 + ":" + simpleDateFormat.parse(str1));
} catch (ParseException e) {
throw new RuntimeException(e);
}
}).start();
new Thread(() -> {
try {
System.out.println(str2 + ":" + simpleDateFormat.parse(str2));
} catch (ParseException e) {
throw new RuntimeException(e);
}
}).start();
}
}
理论上来说,输出的结果应该是成对的: