2012-07-07 27 views
3

使用與recent question中描述的非常相似的模式,對於多線程應用程序,我得到奇怪的日期值(例如,像2025或2035這樣的年份,當源數據中明顯不存在這樣的值時) 。似乎併發問題正在發生。ThreadLocal和SimpleDateFormat數組

的源代碼看起來像

// Various Java DateFormat patterns, e.g. "yyyy-MM-dd". 
private static final String[] DATE_PATTERNS = new String[] {...}; 

private static SimpleDateFormat[] getFormats(final String[] patterns) 
{ 
    ThreadLocal<SimpleDateFormat[]> LOCAL_FORMATS = new ThreadLocal<SimpleDateFormat[]>() 
    { 
     @Override 
     protected SimpleDateFormat[] initialValue() 
     { 
      List<SimpleDateFormat> formatList = new ArrayList<SimpleDateFormat>(); 

      for (String pattern:patterns) 
      { 
       formatList.add(new SimpleDateFormat(pattern)); 
      } 

      return formatList.toArray(new SimpleDateFormat[formatList.size()]); 
     } 
    }; 

    return LOCAL_FORMATS.get(); // Create a thread-local copy 
} 

private static final SimpleDateFormat[] DATE_FORMATS = getFormats(DATE_PATTERNS); 

其靜態初始化後,DATE_FORMATS陣列由許多類,後者又使用數組的SimpleDateFormat對象進行解析或格式化幾個日期字符串訪問。

在這種使用場景中是否會有任何併發​​問題,特別是在使用ThreadLocal

回答

4

是的,可能存在併發問題。你的線程局部變量不起任何作用。它僅在類初始化時使用,用於臨時存儲一組立即檢索並存儲在靜態常量中的日期格式數組。

之後的所有線程總是同時使用相同的日期格式實例,而不會從任何線程局部變量中獲取它們。

的代碼應該寧可:

private static final String[] DATE_PATTERNS = new String[] {...}; 
private static final ThreadLocal<SimpleDateFormat[]> DATE_FORMATS = 
    new ThreadLocal<SimpleDateFormat[]>() { 
     @Override 
     protected SimpleDateFormat[] initialValue() { 
      List<SimpleDateFormat> formatList = new ArrayList<SimpleDateFormat>(); 

      for (String pattern : DATE_PATTERNS) 
      { 
       formatList.add(new SimpleDateFormat(pattern)); 
      } 

      return formatList.toArray(new SimpleDateFormat[formatList.size()]); 
     } 
    }; 

public static SimpleDateFormat[] getDateFormats() { 
    return DATE_FORMATS.get(); 
} 

我也將使用一個不可修改List<SimpleDateFormat>而不是一個數組,更安全。

+0

我實際上是問你在編輯答案時是否建議你的解決方案是正確的。感謝細節!因此,調用getDateFormats()的每個方法將始終爲同一個線程獲取相同的SimpleDateFormat []數組,而對於每個只能初始化一次數組的新線程,正確嗎? – PNS 2012-07-07 16:12:00

+1

你明白了。這是正確的。 – 2012-07-07 16:13:05

+0

當然,可以使用DATE_FORMATS.get()來代替getDateFormats()。如果SimpleDateFormat []數組永遠不會寫入,它應該是線程安全的。再次感謝您的答案! – PNS 2012-07-07 16:23:50

2
// Various Java DateFormat patterns, e.g. "yyyy-mm-dd". 

格式「YYYY-MM-DD」很可能會給你奇怪的結果,因爲「毫米」是分鐘,而不是幾個月。來自javadoc:

M Month in year Month July; Jul; 07 
... 
m Minute in hour Number 30 
+0

沒有實際使用,只是在上面的評論錯字。修正,感謝您的發現! :-) – PNS 2012-07-07 15:58:07