SimpleDateFormat非线程不安全

1 单线程环境

类SimpleDateFormate常用于时间格式转换,在单线程环境下运行结果正常,如下所示

public class MyThread extends Thread {
   private SimpleDateFormatsdf;
   private StringdateString;
 
   publicMyThread(SimpleDateFormatsdf, String dateString) {
      this.sdf =sdf;
      this.dateString =dateString;
   }
 
   Public void run() {
      try {
        Date date = sdf.parse(dateString);
        String newDateString = sdf.format(date).toString();
        if (!newDateString.equals(dateString)) {
           System.out.println("日期字符串: " + dateString + "转换成日期为:" +newDateString);
        }
      } catch(ParseExceptione) {
        e.printStackTrace();
      }
   }
}
public class SingleThreadTest{
   public static void main(String[]args) {
      SimpleDateFormat sdf = newSimpleDateFormat("yyyy-MM-dd");
      String[] dateStringArray = new String[]{"2017-01-01","2017-01-02", "2017-01-03","2017-01-04", "2000-01-05",
           "2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"};
      MyThread[] threadArray = newMyThread[10];
      for(inti = 0; i < 10;i++){
        threadArray[i] = new MyThread(sdf,dateStringArray[i]);
      }
      for(inti = 0; i < 10;i++){
       threadArray[i].run(); //单线程情况下
      }
   }
}

运行结果:


2 并发环境

在并发环境下,使用类SimpleDateFormate进行日期格式转换会出现数据处理不正确,根本原因是存在共享变量calendar

public class MutiThreadTest{
   public static void main(String[]args) {
      SimpleDateFormat sdf = newSimpleDateFormat("yyyy-MM-dd");
      String[] dateStringArray = new String[]{"2017-01-01","2017-01-02", "2017-01-03","2017-01-04", "2000-01-05",
           "2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"};
      MyThread[] threadArray = newMyThread[10];
      for(inti = 0; i < 10;i++){
        threadArray[i] = new MyThread(sdf,dateStringArray[i]);
      }
      for(inti = 0; i < 10;i++){
        threadArray[i].start(); //多线程条件下
      }
   }
}


运行结果:

 


3  解决方法

3.1使用 LocalDate类

 JDK8时间新特性类LocalDate是线程安全,而且使用方法更简单

public class Test {
   public static void main(String[]args) {
      String[] dateStringArray = new String[]{"2017-01-01","2017-01-02", "2017-01-03","2017-01-04", "2000-01-05",
           "2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"};
      MyThread[] threadArray = newMyThread[10];
      for(inti = 0; i < 10;i++){
        threadArray[i] = new MyThread(dateStringArray[i]);
      }
      for(inti = 0; i < 10;i++){
        threadArray[i].start();  //多线程条件下
       
      }
   }
}
public class MyThread extends Thread {
   private StringdateString;

   public MyThread(StringdateString) {
      super();
      this.dateString =dateString;
   }
 
   public void run() {
      LocalDate date = LocalDate.parse(dateString);// JDK8新特性
      if (!date.toString().equals(dateString)) {
        System.out.println("日期字符串: " +dateString + "转换成日期为:" +date);
      }
   }
}
 

3.2 使用ThreadLocal类

类ThreadLocal解决的是变量在不同线程间的隔离性,也就是不同线程拥有自己的隔离值,不同线程中的值可以放入ThreadLocal类中进行保存。

public class DateTools{
   privatestaticThreadLocal<SimpleDateFormat> t1 = newThreadLocal<SimpleDateFormat>();
   publicstaticSimpleDateFormat getSimpleDateFormate(StringdatePattern){
      SimpleDateFormat sdf = null;
      sdf = t1.get();
      if(sdf ==null){
        sdf = newSimpleDateFormat(datePattern);
        t1.set(sdf);
      }
      returnsdf;
   }
}
public class MyThread extends Thread {
   private StringdateString;
  
   public MyThread(StringdateString) {
      super();
      this.dateString =dateString;
   }
 
   publicvoid run(){
      try {
           Date dateRef =DateTools.getSimpleDateFormate("yyyy-MM-dd").parse(dateString);
        String newDateString =  DateTools.getSimpleDateFormate("yyyy-MM-dd").format(dateRef).toString();
        if (!newDateString.equals(dateString)) {
           System.out.println("日期字符串: " + dateString + "转换成日期为:" +newDateString);
        }
      } catch(ParseExceptione) {
        e.printStackTrace();
      }    
   }
}
public class Test {
   publicstatic voidmain(String[]args) {
      String[] dateStringArray = new String[]{"2017-01-01","2017-01-02", "2017-01-03","2017-01-04", "2000-01-05",
           "2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"};
      MyThread[] threadArray = newMyThread[10];
      for(inti = 0; i < 10;i++){
        threadArray[i] = newMyThread(dateStringArray[i]);
      }
      for(inti = 0; i < 10;i++){
        threadArray[i].start();  //多线程条件下
       
      }
   }
}

4 参考文献

[1]  高洪岩, Java多线程编程核心技术. 2015.

[2]  Goetz, B.等, Java 并发编程实战. 2012.

[3]  https://docs.oracle.com/javase/8/docs/api/index.html


原创文章 32 获赞 12 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_35469756/article/details/78886737