最近偶然發現一些數據的日期有錯亂,而且時間出錯格式無規律,有些去了1970年了,有些月份錯了,有些號數變了,而日志上看并沒有異常信息!
根據用戶反應,常出現在某個批量更新操作中,于是乎,也按照用戶描述的,線下操作了數遍,也沒有出現這種情況。
有趣的是,就算在線上操作,也并不是一定會出現這種問題,只是偶然!
我開始懷疑底層代碼問題了,因為那個操作,并沒有修改到日期相關的字段,為了證實這點,經過我一番的排查,
問題終于定位在DateUtil.parse等方法上,parse方法調用了一個靜態的simpleDateFormat.parse方法,為什么?!為什么這個方法不穩定的?
仔細閱讀了java.util.SimpleDateFormat的api,發現此信息:
Synchronization
Date formats are not synchronized. It is recommended to create separate format instances for each thread.
If multiple threads access a format concurrently, it must be synchronized externally.
很明顯simpledateformat并不是線程同步的,以致并發的時候不安全!為了證實這點于是乎寫了一個簡單的測試程序。
package com.leisure;
import java.text.ParseException;
public class TestSimpleDateFormatThreadSafe extends Thread {
@Override
public void run() {
while(true) {
try {
this.join(2000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
System.out.println(DateUtil.parse("2011-10-11 06:02:20"));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
for(int i = 0; i < 20; i++)
new TestSimpleDateFormatThreadSafe().start();
}
}
package com.leisure;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtil {
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static Date parse(String str) throws ParseException {
return sdf.parse(str);
}
}
輸出結果:
Tue Oct 11 18:02:20 CST 2011
Tue Oct 11 18:02:20 CST 2011
Sun Oct 11 18:02:20 CST 1970
Tue Oct 11 18:02:20 CST 2011
Thu Jan 01 18:02:20 CST 1970
Sat Dec 11 18:02:20 CST 2010
Tue Oct 11 18:02:20 CST 2011
Exception in thread "Thread-18" java.lang.NumberFormatException: multiple points
at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)
at java.lang.Double.parseDouble(Unknown Source)
at java.text.DigitList.getDouble(Unknown Source)
at java.text.DecimalFormat.parse(Unknown Source)
at java.text.SimpleDateFormat.subParse(Unknown Source)
at java.text.SimpleDateFormat.parse(Unknown Source)
at java.text.DateFormat.parse(Unknown Source)
at com.leisure.DateUtil.parse(DateUtil.java:12)
at com.leisure.TestSimpleDateFormatThreadSafe.run(TestSimpleDateFormatThreadSafe.java:16)
Fri Dec 23 19:02:20 CST 2011
Fri Dec 23 18:02:20 CST 2011
輸出結果很明顯了,跟線上數據出現的問題基本一致。不過按照這里看到的結果,有報錯,再仔細閱讀了應用的底層代碼,
某個位置攔截了部份異常,沒有記錄也沒有向上拋出處理,到這里,我只想問一句:底層代碼誰寫的?