首页 > 代码库 > SimpleDateFormat线程不安全(转)

SimpleDateFormat线程不安全(转)

 

 

 有三种方法可以解决以上安全问题。
  1).使用同步

 1 package com.bijian.study.date; 2  3 import java.text.ParseException; 4 import java.text.SimpleDateFormat; 5 import java.util.Date; 6  7 public class DateUtil02 implements DateUtilInterface { 8  9     private SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");10     11     @Override12     public void format(Date date) {13         System.out.println(dateformat.format(date));14     }15 16     @Override17     public void parse(String str) {18         try {19             synchronized(dateformat){20                 System.out.println(dateformat.parse(str));21             }22         } catch (ParseException e) {23             e.printStackTrace();24         }25     }26 }


修改DateMainTest.java的DateUtilInterface dateUtil = new DateUtil01();为DateUtilInterface dateUtil = new DateUtil02();测试OK。

        不过,当线程较多时,当一个线程调用该方法时,其他想要调用此方法的线程就要block,这样的操作也会一定程度上影响性能。

 

  2).每次使用时,都创建一个新的SimpleDateFormat实例

 1 package com.bijian.study.date; 2  3 import java.text.ParseException; 4 import java.text.SimpleDateFormat; 5 import java.util.Date; 6  7 public class DateUtil03 implements DateUtilInterface { 8  9     @Override10     public void format(Date date) {11         12         SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");13         System.out.println(dateformat.format(date));14     }15 16     @Override17     public void parse(String str) {18         try {19             SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");20             System.out.println(dateformat.parse(str));21         } catch (ParseException e) {22             e.printStackTrace();23         }24     }25 }

修改DateMainTest.java的DateUtilInterface dateUtil = new DateUtil02();为DateUtilInterface dateUtil = new DateUtil03();测试OK。

  

  3).借助ThreadLocal对象每个线程只创建一个实例

     借助ThreadLocal对象每个线程只创建一个实例,这是推荐的方法

     对于每个线程SimpleDateFormat不存在影响他们之间协作的状态,为每个线程创建一个SimpleDateFormat变量的拷贝或者叫做副本,代码如下:

 1 package com.bijian.study.date; 2  3 import java.text.DateFormat; 4 import java.text.ParseException; 5 import java.text.SimpleDateFormat; 6 import java.util.Date; 7  8 public class DateUtil04 implements DateUtilInterface { 9 10     private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";11 12     // 第一次调用get将返回null13     private static ThreadLocal threadLocal = new ThreadLocal(){14         protected Object initialValue() {  15             return null;//直接返回null  16         } 17     };18     19     // 获取线程的变量副本,如果不覆盖initialValue,第一次get返回null,故需要初始化一个SimpleDateFormat,并set到threadLocal中20     public static DateFormat getDateFormat() {21         DateFormat df = (DateFormat) threadLocal.get();22         if (df == null) {23             df = new SimpleDateFormat(DATE_FORMAT);24             threadLocal.set(df);25         }26         return df;27     }28 29     @Override30     public void parse(String textDate) {31 32         try {33             System.out.println(getDateFormat().parse(textDate));34         } catch (ParseException e) {35             e.printStackTrace();36         }37     }38 39     @Override40     public void format(Date date) {41         System.out.println(getDateFormat().format(date));42     }43 }

创建一个ThreadLocal类变量,这里创建时用了一个匿名类,覆盖了initialValue方法,主要作用是创建时初始化实例。

         也可以采用下面方式创建。

 

 1 package com.bijian.study.date; 2  3 import java.text.DateFormat; 4 import java.text.ParseException; 5 import java.text.SimpleDateFormat; 6 import java.util.Date; 7  8 public class DateUtil05 implements DateUtilInterface { 9 10     private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";11     12     @SuppressWarnings("rawtypes")13     private static ThreadLocal threadLocal = new ThreadLocal() {14         protected synchronized Object initialValue() {15             return new SimpleDateFormat(DATE_FORMAT);16         }17     };18 19     public DateFormat getDateFormat() {20         return (DateFormat) threadLocal.get();21     }22 23     @Override24     public void parse(String textDate) {25 26         try {27             System.out.println(getDateFormat().parse(textDate));28         } catch (ParseException e) {29             e.printStackTrace();30         }31     }32 33     @Override34     public void format(Date date) {35         System.out.println(getDateFormat().format(date));36     }37 }

修改DateMainTest.java的DateUtilInterface dateUtil = new DateUtil03();为DateUtilInterface dateUtil = new DateUtil04();或者DateUtilInterface dateUtil = new DateUtil05();测试OK。

 

      最后,当然也可以使用apache commons-lang包的DateFormatUtils或者FastDateFormat实现,apache保证是线程安全的,并且更高效。

 

     附:Oracle官方bug说明: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6178997

 

  转自 http://bijian1013.iteye.com/blog/1873336

 

 

 

SimpleDateFormat线程不安全(转)