这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战
前言
经常听到开发大佬说不建议用SimpleDateFormat,包括阿里巴巴java开发手册也写了“SimpleDateFormat是线程不安全的类,一般不要定义为static变量,如果定义为static,必须加锁,或者使用 DateUtils 工具类。”
可是,为什么说SimpleDateFormat是线程不安全的类呢?要想证明这个问题,首先要聚一个例子,看看在多线程环境下,使用SimpleDateFormat会怎么样。
1 | typescript复制代码public static void main(String[] args) { |
在同个一个线程中,多次操作同一个时间new Date(),比较前后操作的结果是否一样。一样,则代表是现场安全的。
在看一下运行的结果
发现确实在某些线程中,前后的时间不一致。那就说明SimpleDateFormat确实是线程不安全的。
看一下format方法的源码
1 | ini复制代码private StringBuffer format(Date date, StringBuffer toAppendTo, |
可以看到,多个线程之间共享变量calendar,并修改calendar。因此在多线程环境下,当多个线程同时使用相同的SimpleDateFormat对象(如static修饰)的话,如调用format方法时,多个线程会同时调用calender.setTime方法,导致time被别的线程修改,因此线程是不安全的。
此外,parse方法也是线程不安全的,parse方法实际调用的是CalenderBuilder的establish来进行解析,其方法中主要步骤不是原子操作。
想要避免,要不就加锁、要不就在方法内new SimpleDateFormat。不管是哪种,都是对性能有所影响的。JDK8的DateTimeFormatter是一个不错的解决方式。我们来看看DateTimeFormatter是怎么保证线程安全的。
1 | swift复制代码public final class DateTimeFormatter { |
DateTimeFormatter的类是用final修饰的,成员变量也是用final修饰的。这就代表DateTimeFormatter是个不可变的对象,意味着线程B对象无法修改线程A的DateTimeFormatter对象中的变量。线程B只能自己新建一个DateTimeFormatter对象。
总结
简述了SimpleDateFormat为什么是线程不安全的和DateTimeFormatter为什么是线程安全的之后,我们在实际开发中,要努力去规范我们的代码,在使用封装好的工具类时,也要知其原理,避免问题。
如果项目是JDK8的话,在处理时间问题时,不妨直接用DateTimeFormatter来试试!
本文转载自: 掘金