SimpleDateFormat線程不安全


1,問題引發

 1 @Test  2 public void testParse() {  3     ExecutorService executorService = Executors.newCachedThreadPool();  4     List<String> dateStrList = Lists.newArrayList(  5             "2018-04-01 10:00:01",  6             "2018-04-02 11:00:02",  7             "2018-04-03 12:00:03",  8             "2018-04-04 13:00:04",  9             "2018-04-05 14:00:05"
10  ); 11     SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); 12     for (String str : dateStrList) { 13         executorService.execute(() -> { 14             try { 15  simpleDateFormat.parse(str); 16                 TimeUnit.SECONDS.sleep(1); 17             } catch (Exception e) { 18  e.printStackTrace(); 19  } 20  }); 21  } 22 }

報錯

2,原因

  在SimpleDateFormat轉換日期是通過Calendar對象來操作的,SimpleDateFormat繼承DateFormat類,DateFormat類中維護一個Calendar對象。

 

  通過DateFormat類中的注釋可知:此處Calendar實例被用來進行日期-時間計算,既被用於format方法也被用於parse方法!

  在parse方法的最后,會調用CalendarBuilder的establish方法,入參就是SimpleDateFormat維護的Calendar實例,在establish方法中會調用calendar的clear方法,如下:

  可知SimpleDateFormat維護的用於format和parse方法計算日期-時間的calendar被清空了,如果此時線程A將calendar清空且沒有設置新值,線程B也進入parse方法用到了SimpleDateFormat對象中的calendar對象,此時就會產生線程安全問題。

3,解決方法

  每一個使用SimpleDateFormat對象進行日期-時間進行format和parse方法的時候就創建一個新的SimpleDateFormat對象,用完就銷毀即可!

 1 /**
 2  * 模擬並發環境下使用SimpleDateFormat的parse方法將字符串轉換成Date對象  3  */
 4 @Test  5 public void testParseThreadSafe() {  6     ExecutorService executorService = Executors.newCachedThreadPool();  7     List<String> dateStrList = Lists.newArrayList(  8             "2018-04-01 10:00:01",  9             "2018-04-02 11:00:02", 10             "2018-04-03 12:00:03", 11             "2018-04-04 13:00:04", 12             "2018-04-05 14:00:05"
13  ); 14     for (String str : dateStrList) { 15         executorService.execute(() -> { 16             try { 17                 //創建新的SimpleDateFormat對象用於日期-時間的計算
18                 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); 19  simpleDateFormat.parse(str); 20                 TimeUnit.SECONDS.sleep(1); 21                 simpleDateFormat = null; //銷毀對象
22             } catch (Exception e) { 23  e.printStackTrace(); 24  } 25  }); 26  } 27 }

  使用SimpleDateFormat對象進行日期-時間計算時,如果SimpleDateFormat是多個線程共享的就會有線程安全問題!應該讓每一個線程都有一個獨立的SimpleDateFormat對象用於日期-時間的計算!此時就可以使用ThreadLocal將SimpleDateFormat綁定到線程上,是的該線程上的日期-時間計算順序的使用SimpleDateFormat對象,這樣也可以避免線程安全問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM