线程安全性:
一个类是线程安全的是指在被多个线程访问时,类可以持续进行正确的行为.不用考虑这些线程运行时环境下的调度和交替.
三种方法解决SimpleDateFormat的线程不安全性
在Java项目中,我们通常会自己写一个DateUtil类,处理日期和字符串的转换。如下
public class DateUtil{
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
public static formatDateToYYYYMMDDStr(Date date){
return sdf.format(date);
}
public static formatYYYYMMDDStrToDate(String str){
return sdf.parse(str);
}
}
然而,由于SimpleDateFormat类不是线程安全的,所以在多线程的环境下,往往会出现意想不到的结果。
有三种方法可以解决以上问题。
1)每次使用时,都创建一个新的SimpleDateFormat实例。如果使用不是很频繁时,可以使用此方法,这样可以降低创建新对象的开销。
public class DateUtil{
public static formatDateToYYYYMMDDStr(Date date){
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
return sdf.format(date);
}
public static formatYYYYMMDDStrToDate(String str){
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
return sdf.parse(str);
}
}
2)使用同步:
public class DateUtil{
private SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
private Date parse(String dateStr) throws ParseException{
synchronized (sdf){
return sdf.parse(dateStr);
}
}
private String format(Date date){
synchronized (sdf){
return sdf.format(dateStr);
}
}
}
不过,当线程较多时,当一个线程调用该方法时,其他想要调用此方法的线程就要block,这样的操作也会一定程度上影响性能。
3)个人最推荐的是第三种方法,那就是借助ThreadLocal对象每个线程只创建一个实例。
public class DateUtil {
private static final String DATE_FORMAT = "yyyyMMdd";
@SuppressWarnings("rawtypes")
private static ThreadLocal threadLocal = new ThreadLocal() {
protected synchronized Object initialValue() {
return new SimpleDateFormat(DATE_FORMAT);
}
};
public static DateFormat getDateFormat() {
return (DateFormat) threadLocal.get();
}
public static Date parse(String textDate) throws ParseException {
return getDateFormat().parse(textDate);
}
}