1. 程式人生 > >SimpleDateFormat多執行緒下的異常

SimpleDateFormat多執行緒下的異常

  今天在生產上碰到一個怪異的問題,之前一直跑的很好的xml轉object程式,在日期轉化的過程中報錯的,經過排查原因,原來是由於SimpleDateFormat在多執行緒下執行造成的結果。
demo例子如下:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
*日期格式化
**/
public class DateFormat {
    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd"
); public Date parseDate(String str ){ if(str == null) return null; try { return SDF.parse(str); } catch (ParseException e) { e.printStackTrace(); } return null; } } public class Test { public static void main
(String[] args) { for(int i=0;i<10;i++){ Thread thread = new Thread(new Runnable() { @Override public void run() { DateFormat sdf = new DateFormat(); System.out.println(sdf.parseDate("2016-10-19")); } }); thread.start(); } } }

執行錯誤資訊:

Exception in thread "Thread-4" Exception in thread "Thread-3" java.lang.NumberFormatException: For input string: "..10011001EE22"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Long.parseLong(Long.java:430)
    at java.lang.Long.parseLong(Long.java:483)
    at java.text.DigitList.getLong(DigitList.java:194)
    at java.text.DecimalFormat.parse(DecimalFormat.java:1316)
    at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
    at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
    at java.text.DateFormat.parse(DateFormat.java:355)
    at com.busap.DateFormat.parseDate(DateFormat.java:14)
    at com.busap.Abc$1.run(Abc.java:19)
    at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-2" java.lang.NumberFormatException: multiple points
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1110)
    at java.lang.Double.parseDouble(Double.java:540)
    at java.text.DigitList.getDouble(DigitList.java:168)
    at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
    at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
    at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
    at java.text.DateFormat.parse(DateFormat.java:355)
    at com.busap.DateFormat.parseDate(DateFormat.java:14)
    at com.busap.Abc$1.run(Abc.java:19)
    at java.lang.Thread.run(Thread.java:745)
java.lang.NumberFormatException: multiple points
    at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1110)
    at java.lang.Double.parseDouble(Double.java:540)
    at java.text.DigitList.getDouble(DigitList.java:168)
    at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
    at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
    at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
    at java.text.DateFormat.parse(DateFormat.java:355)
    at com.busap.DateFormat.parseDate(DateFormat.java:14)
    at com.busap.Abc$1.run(Abc.java:19)
    at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-3" java.lang.NumberFormatException: For input string: ""
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Long.parseLong(Long.java:453)
    at java.lang.Long.parseLong(Long.java:483)
    at java.text.DigitList.getLong(DigitList.java:194)
    at java.text.DecimalFormat.parse(DecimalFormat.java:1316)
    at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
    at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
    at java.text.DateFormat.parse(DateFormat.java:355)
    at com.busap.DateFormat.parseDate(DateFormat.java:14)
    at com.busap.Abc$1.run(Abc.java:13)
    at java.lang.Thread.run(Thread.java:745)

各種異常接踵而至,原因就是SimpleDateFormat不是執行緒安全類。要想解決上述問題,去掉static final 修飾符,這樣每個執行緒生成一個SimpleDateFormat,執行緒之間互不影響就解決了上面的問題。不過如果在大併發的情況,就會生成一堆SimpleDateFormat類(static final 修飾符原意也是為了解決這個問題),為了優化大併發的情況,可以使用ThreadLocal。在同一個執行緒內共享一個SimpleDateFormat,總比多次呼叫生成多個的好。