一、问题
负责日期转换和格式化的SimpleDateFonnat类,在多线程的环境中,很容易出现各种问题,比如转换的时间不正确、线程被挂死、抛出NumberFormatException异常等,因为该类并不是线程安全的
java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:601)
at java.lang.Long.parseLong(Long.java:631)
at java.text.DigitList.getLong(DigitList.java:195)
at java.text.DecimalFormat.parse(DecimalFormat.java:2051)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at DateFormatTest.run(DateFormatTest.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
二、方案
1、局部变量
高并发的情况下会大量的创建和销毁,非常耗费资源
public String format(Date date){
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return dateFormat.format(date);
}
2、同步方法/块每次执行时都会加锁,高并发时对性能产生很大影响
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static String formatDate(Date date)throws ParseException{
synchronized(DATE_FORMAT){
return DATE_FORMAT.format(date);
}
}
3、ThreadLocal
为每个线程创建一个Format对象,线程只使用自己的
private static ThreadLocal<DateFormat> LOCAL_DATE_FORMAT = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
public static Date parse(String dateStr) throws ParseException {
return LOCAL_DATE_FORMAT.get().parse(dateStr);
}
4、第三方工具比如 Joda-Time 类库,或者 Apache的 commons-lang 包中的 DateFormatUtils 与 FastDateFormat 工具类
5、JDK8关于Date和Time的新API