J2SE - 關於SimpleDateFonnat的執行緒安全問題

襲冷發表於2018-05-18

一、問題

    負責日期轉換和格式化的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





相關文章