在项目中,经常需要将日期在String和Date之间做转化,此时需要使用SimpleDateFormat类。使用SimpleDateFormat类的parse方法,可以将满足格式要求的字符串转换成Date对象,使用SimpleDateFormat类的format方法,可以将Date类型的对象转换成一定格式的字符串。
重点注意:SimpleDateFormat并非是线程安全的。
1.测试代码
场景1
@Test
public void testParse() {
ExecutorService executorService = Executors.newCachedThreadPool();
List<String> dateStrList = Lists.newArrayList(
"2019-02-11 10:00:01",
"2018-02-12 11:00:02",
"2018-02-13 12:00:03",
);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
for (String str : dateStrList) {
executorService.execute(() -> {
try {
simpleDateFormat.parse(str);
TimeUnit.SECONDS.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
场景2:
在executorService 提交的并发任务中,有运行实例中包含SimpleDateFormat 属性,进行日期格式化,线上会有概率报异常。
2.原因分析
在SimpleDateFormat转换日期底层是通过Calendar对象来操作的,SimpleDateFormat继承DateFormat类,DateFormat类中维护一个Calendar对象,代码如下:
calender 做为DateFormat 的属性之一,用来parse 和format,A线程和B 线程公用时可能会产生线程安全的问题。
3.解决方案:
在具体调用中,new 一个新的format对象即可。
@Test
public void testParse() {
ExecutorService executorService = Executors.newCachedThreadPool();
List<String> dateStrList = Lists.newArrayList(
"2019-02-11 10:00:01",
"2018-02-12 11:00:02",
"2018-02-13 12:00:03",
);
for (String str : dateStrList) {
executorService.execute(() -> {
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
simpleDateFormat.parse(str);
TimeUnit.SECONDS.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
});
}
}