首页 > 代码库 > 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线程不安全(转)