在一次项目上线的时候,发现老是出现数据丢失问题,通过日志发现SimpleDateFormat是线程不安全的!!!
代码:
private static SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static Date string2DateTime(String dateStr) {
Date date = null;
try {
if (string != null && !string.trim().equals("")) {
date = dateTimeFormat.parse(string);
}
} catch (Exception e) {
logger.warn("字符串转日期值失败!" + e.getMessage());
}
return date;
}
报错:
2018-12-04 18:12:27.696 WARN pool-1-thread-9 128 [DateUtil.java:128] 字符串转日期值失败!For input string: "E111133E2"
2018-12-04 18:12:27.696 WARN pool-1-thread-10 128 [DateUtil.java:128] 字符串转日期值失败!For input string: "E111133"
2018-12-04 18:12:27.696 WARN pool-1-thread-2 128 [DateUtil.java:128] 字符串转日期值失败!For input string: "E111133E2.11E2"
2018-12-04 18:12:27.696 WARN pool-1-thread-8 128 [DateUtil.java:128] 字符串转日期值失败!For input string: "E111133E2.11E22E2"
2018-12-04 18:12:27.696 WARN pool-1-thread-5 128 [DateUtil.java:128] 字符串转日期值失败!For input string: "E111133E2.11E22"
- 通过上述可见报错日志可见,发生了类型转换异常,debug发现传入的参数dateStr是正确的时间参数,但是抛出了报错日志中的错误。后来搜索发现是SimpleDateFormat是线程不安全的。
解决方案:
1. 将SimpleDateFormat定义成局部变量。
缺点:每调用一次方法就会创建一个SimpleDateFormat对象,方法结束又要作为垃圾回收。
2.方法加同步锁synchronized,在同一时刻,只有一个线程可以执行类中的某个方法。
缺点:性能较差,每次都要等待锁释放后其他线程才能进入。
3.使用第三方库joda-time,由第三方考虑线程不安全的问题。(可以使用)
4.使用ThreadLocal:每个线程拥有自己的SimpleDateFormat对象。(推荐使用)