zoukankan      html  css  js  c++  java
  • SimpleDateFormat非线程安全

    前言:在一次ReviewBoard上,被老大指出SimpleDateFormat存在线程安全的问题,所以特地将其提出来看看,并提出其解决方案。


    1.SimpleDateFormat线程不安全的表现

    这里通过代码来复现SimpleDateFormat线程不安全的表现,具体代码如下:

     1 public class SimpleDateFormatTest extends Thread {
     2 
     3     private SimpleDateFormat sdf;
     4 
     5     private String dateString;
     6 
     7     public SimpleDateFormatTest(SimpleDateFormat sdf, String dateString) {
     8         this.sdf = sdf;
     9         this.dateString = dateString;
    10     }
    11 
    12     @Override
    13     public void run() {
    14         try {
    15             Date date = sdf.parse(dateString);
    16             System.out.println(date.toString());
    17         } catch (Exception e) {
    18             e.printStackTrace();
    19         }
    20     }
    21 
    22     public static void main(String[] args) {
    23 
    24         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    25 
    26         String[] dateStringArray = {"2001-01-01", "2001-01-01", "2001-01-01", "2001-01-01", "2001-01-01"};
    27 
    28         SimpleDateFormatTest[] threadArray = new SimpleDateFormatTest[5];
    29 
    30         for (int i = 0; i < 5; i++) {
    31             threadArray[i] = new SimpleDateFormatTest(sdf, dateStringArray[i]);
    32         }
    33         for (int i = 0; i < 5; i++) {
    34             threadArray[i].start();
    35         }
    36     }
    37 }

    注:运行5个线程来进行时间字符串的转换。

    运行结果如下:

    运行结果抛出了异常,通过查看SimpleDateFormat知道了原因:

    SimpleDateFormat源码的注解中明确指出在进行日期转换的时候是不同步的,也就会出现线程安全问题,因此建议为每个线程都创建一个SimpleDateFormat对象,如果在多线程环境中要使用一个SimpleDateFormat对象,就必须保证其同步。

    修改以上源码为每个线程都创建一个SimpleDateFormat对象,可解决该问题。源码如下:

     1 public class SimpleDateFormatTest extends Thread {
     2 
     3     private SimpleDateFormat sdf;
     4 
     5     private String dateString;
     6 
     7     public SimpleDateFormatTest(SimpleDateFormat sdf, String dateString) {
     8         this.sdf = sdf;
     9         this.dateString = dateString;
    10     }
    11 
    12     @Override
    13     public void run() {
    14         try {
    15             Date date = sdf.parse(dateString);
    16             System.out.println(date.toString());
    17         } catch (Exception e) {
    18             e.printStackTrace();
    19         }
    20     }
    21 
    22     public static void main(String[] args) {
    23 
    24 //        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    25 
    26         String[] dateStringArray = {"2001-01-01", "2001-01-01", "2001-01-01", "2001-01-01", "2001-01-01"};
    27 
    28         SimpleDateFormatTest[] threadArray = new SimpleDateFormatTest[5];
    29 
    30         for (int i = 0; i < 5; i++) {
    31             SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    32             threadArray[i] = new SimpleDateFormatTest(sdf, dateStringArray[i]);
    33         }
    34         for (int i = 0; i < 5; i++) {
    35             threadArray[i].start();
    36         }
    37     }
    38

    运行结果如下(正常运行为出现任何线程安全问题):

    2.利用FastDateFormat/DateFormatUtils替代SimpleDateFormat

    Apache提供的这两个类在时间上的转换是线程安全的,因此可以用其对SimpleDateFormat进行替代。

    下面用FastDateFormat进行替代(使用DateFormatUtils效果一样)具体代码如下:

     1 public class SimpleDateFormatTest extends Thread {
     2 
     3 //    private SimpleDateFormat sdf;
     4 
     5     private FastDateFormat fastDateFormat;
     6 
     7     private String dateString;
     8 
     9     public SimpleDateFormatTest(FastDateFormat fdf, String dateString) {
    10         this.fastDateFormat = fdf;
    11         this.dateString = dateString;
    12     }
    13 
    14     @Override
    15     public void run() {
    16         try {
    17             Date date = fastDateFormat.parse(dateString);
    18             System.out.println(date.toString());
    19         } catch (Exception e) {
    20             e.printStackTrace();
    21         }
    22     }
    23 
    24     public static void main(String[] args) {
    25 
    26 //        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    27 
    28         FastDateFormat fastDateFormat = FastDateFormat.getInstance("yyyy-MM-dd");
    29         String[] dateStringArray = {"2001-01-01", "2001-01-01", "2001-01-01", "2001-01-01", "2001-01-01"};
    30 
    31         SimpleDateFormatTest[] threadArray = new SimpleDateFormatTest[5];
    32 
    33         for (int i = 0; i < 5; i++) {
    34             threadArray[i] = new SimpleDateFormatTest(fastDateFormat, dateStringArray[i]);
    35         }
    36         for (int i = 0; i < 5; i++) {
    37             threadArray[i].start();
    38         }
    39     }
    40 }

    运行结果如下,在多线程环境中未出现线程安全问题:

    总结

    通过以上实验,在下次使用SimpleDateFormat的时候,需要特别注意,最好是使用FastDateFormat,或者DateFormatUtils进行替代,防止在多线程环境中出现线程安全问题,具体非线程安全问题,继续研究源码。

    补充:阅读FastDateFormat的源码可知,其内部变量都是final域的,保证了线程安全。


    by Shawn Chen,2018.11.21日,上午。

  • 相关阅读:
    C语言中scanf函数的实现
    Express中设置cookie,session,token
    ajax2.0提供的FormData
    将json字符串解析为对象的三种方式
    ajax中的跨域问题
    html5中的图片预览
    jQuery中的ajax
    jQuery中的表单序列化
    实现一个瀑布流
    ajax
  • 原文地址:https://www.cnblogs.com/developer_chan/p/9990450.html
Copyright © 2011-2022 走看看