• SimpleDateFormat线程不安全


    1,问题引发

     1 @Test
     2 public void testParse() {
     3     ExecutorService executorService = Executors.newCachedThreadPool();
     4     List<String> dateStrList = Lists.newArrayList(
     5             "2018-04-01 10:00:01",
     6             "2018-04-02 11:00:02",
     7             "2018-04-03 12:00:03",
     8             "2018-04-04 13:00:04",
     9             "2018-04-05 14:00:05"
    10     );
    11     SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    12     for (String str : dateStrList) {
    13         executorService.execute(() -> {
    14             try {
    15                 simpleDateFormat.parse(str);
    16                 TimeUnit.SECONDS.sleep(1);
    17             } catch (Exception e) {
    18                 e.printStackTrace();
    19             }
    20         });
    21     }
    22 }

    报错

    2,原因

      在SimpleDateFormat转换日期是通过Calendar对象来操作的,SimpleDateFormat继承DateFormat类,DateFormat类中维护一个Calendar对象。

     

      通过DateFormat类中的注释可知:此处Calendar实例被用来进行日期-时间计算,既被用于format方法也被用于parse方法!

      在parse方法的最后,会调用CalendarBuilder的establish方法,入参就是SimpleDateFormat维护的Calendar实例,在establish方法中会调用calendar的clear方法,如下:

      可知SimpleDateFormat维护的用于format和parse方法计算日期-时间的calendar被清空了,如果此时线程A将calendar清空且没有设置新值,线程B也进入parse方法用到了SimpleDateFormat对象中的calendar对象,此时就会产生线程安全问题。

    3,解决方法

      每一个使用SimpleDateFormat对象进行日期-时间进行format和parse方法的时候就创建一个新的SimpleDateFormat对象,用完就销毁即可!

     1 /**
     2  * 模拟并发环境下使用SimpleDateFormat的parse方法将字符串转换成Date对象
     3  */
     4 @Test
     5 public void testParseThreadSafe() {
     6     ExecutorService executorService = Executors.newCachedThreadPool();
     7     List<String> dateStrList = Lists.newArrayList(
     8             "2018-04-01 10:00:01",
     9             "2018-04-02 11:00:02",
    10             "2018-04-03 12:00:03",
    11             "2018-04-04 13:00:04",
    12             "2018-04-05 14:00:05"
    13     );
    14     for (String str : dateStrList) {
    15         executorService.execute(() -> {
    16             try {
    17                 //创建新的SimpleDateFormat对象用于日期-时间的计算
    18                 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    19                 simpleDateFormat.parse(str);
    20                 TimeUnit.SECONDS.sleep(1);
    21                 simpleDateFormat = null; //销毁对象
    22             } catch (Exception e) {
    23                 e.printStackTrace();
    24             }
    25         });
    26     }
    27 }

      使用SimpleDateFormat对象进行日期-时间计算时,如果SimpleDateFormat是多个线程共享的就会有线程安全问题!应该让每一个线程都有一个独立的SimpleDateFormat对象用于日期-时间的计算!此时就可以使用ThreadLocal将SimpleDateFormat绑定到线程上,是的该线程上的日期-时间计算顺序的使用SimpleDateFormat对象,这样也可以避免线程安全问题。

  • 相关阅读:
    header
    panel----单个基础版
    vue-demo
    js不同类型变量比较
    reset.css
    关于各个浏览器的兼容问题
    git
    AMD与CMD区别
    喜欢前端的看过来哦
    js中数组去重的几种方法
  • 原文地址:https://www.cnblogs.com/guanghe/p/11495577.html
Copyright © 2020-2023  润新知