java中ThreadLocal作用與執行緒安全問題

破棉襖發表於2014-07-16

1.概念:

ThreadLocal是什麼呢?其實ThreadLocal並非是一個執行緒的本地實現版本,它並不是一個Thread,而是threadlocalvariable(執行緒區域性變數)。也許把它命名為ThreadLocalVar更加合適。執行緒區域性變數(ThreadLocal)其實的功用非常簡單,就是為每一個使用該變數的執行緒都提供一個變數值的副本,是Java中一種較為特殊的執行緒繫結機制,是每一個執行緒都可以獨立地改變自己的副本,而不會和其它執行緒的副本衝突。


2.以SimpleDateFormat執行緒非安全示例:

SimpleDateFormat(下面簡稱sdf)類內部有一個Calendar物件引用,它用來儲存和這個sdf相關的日期資訊,例如sdf.parse(dateStr), sdf.format(date) 諸如此類的方法引數傳入的日期相關String, Date等等, 都是交友Calendar引用來儲存的.這樣就會導致一個問題,如果你的sdf是個static的, 那麼多個thread 之間就會共享這個sdf, 同時也是共享這個Calendar引用, 並且, 觀察 sdf.parse() 方法,你會發現有如下的呼叫:

  1. Date parse() {
  2.   calendar.clear(); // 清理calendar
  3.      ... // 執行一些操作, 設定 calendar 的日期什麼的
  4.   calendar.getTime(); // 獲取calendar的時間
  5. }


這裡會導致的問題就是, 如果 執行緒A 呼叫了 sdf.parse(), 並且進行了 calendar.clear()後還未執行calendar.getTime()的時候,執行緒B又呼叫了sdf.parse(), 這時候執行緒B也執行了sdf.clear()方法, 這樣就導致執行緒A的的calendar資料被清空了(實際上A,B的同時被清空了). 又或者當 A 執行了calendar.clear() 後被掛起, 這時候B 開始呼叫sdf.parse()並順利i結束, 這樣 A 的 calendar記憶體儲的的date 變成了後來B設定的calendar的date
 
3.解決方案:
 
		
  1. private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
  2.     @SuppressWarnings("rawtypes")
  3.     private static ThreadLocal threadLocal = new ThreadLocal() {
  4.         protected synchronized Object initialValue() {
  5.             return new SimpleDateFormat(DATE_FORMAT);
  6.         }
  7.     };
  8.  
  9. DateFormat df = (DateFormat) threadLocal.get();

 
 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29754888/viewspace-1220276/,如需轉載,請註明出處,否則將追究法律責任。

相關文章