leisure

          JAVA - exceed,helloworld
          隨筆 - 50, 文章 - 0, 評論 - 11, 引用 - 0
          數(shù)據(jù)加載中……

          SimpleDateFormat多線程并發(fā)下的不安全隱患

          最近偶然發(fā)現(xiàn)一些數(shù)據(jù)的日期有錯亂,而且時間出錯格式無規(guī)律,有些去了1970年了,有些月份錯了,有些號數(shù)變了,而日志上看并沒有異常信息!

          根據(jù)用戶反應(yīng),常出現(xiàn)在某個批量更新操作中,于是乎,也按照用戶描述的,線下操作了數(shù)遍,也沒有出現(xiàn)這種情況。

          有趣的是,就算在線上操作,也并不是一定會出現(xiàn)這種問題,只是偶然!

          我開始懷疑底層代碼問題了,因為那個操作,并沒有修改到日期相關(guān)的字段,為了證實這點,經(jīng)過我一番的排查,
          問題終于定位在DateUtil.parse等方法上,parse方法調(diào)用了一個靜態(tài)的simpleDateFormat.parse方法,為什么?!為什么這個方法不穩(wěn)定的?
          仔細閱讀了java.util.SimpleDateFormat的api,發(fā)現(xiàn)此信息:

          Synchronization

          Date formats are not synchronized. It is recommended to create separate format instances for each thread.
          If multiple threads access a format concurrently, it must be synchronized externally.


          很明顯simpledateformat并不是線程同步的,以致并發(fā)的時候不安全!為了證實這點于是乎寫了一個簡單的測試程序。

          package com.leisure;
          import java.text.ParseException;
          public class TestSimpleDateFormatThreadSafe extends Thread {
              @Override
              public void run() {
                  while(true) {
                      try {
                          this.join(2000);
                      } 
          catch (InterruptedException e1) {
                          e1.printStackTrace();
                      }
                      try {
                          System.out.println(DateUtil.parse(
          "2011-10-11 06:02:20"));
                      } 
          catch (ParseException e) {
                          e.printStackTrace();
                      }
                  }
              }

              public static void main(String[] args) {
                  for(int i = 0; i < 20; i++)
                      new TestSimpleDateFormatThreadSafe().start();
              }
          }

          package com.leisure;

          import java.text.ParseException;
          import java.text.SimpleDateFormat;
          import java.util.Date;

          public class DateUtil {
              
          private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

              
          public static Date parse(String str) throws ParseException {
                  
          return sdf.parse(str);
              }
          }

          輸出結(jié)果:

          Tue Oct 11 18:02:20 CST 2011

          Tue Oct 11 18:02:20 CST 2011

          Sun Oct 11 18:02:20 CST 1970

          Tue Oct 11 18:02:20 CST 2011

          Thu Jan 01 18:02:20 CST 1970

          Sat Dec 11 18:02:20 CST 2010

          Tue Oct 11 18:02:20 CST 2011

          Exception in thread "Thread-18" java.lang.NumberFormatException: multiple points

          at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)

          at java.lang.Double.parseDouble(Unknown Source)

          at java.text.DigitList.getDouble(Unknown Source)

          at java.text.DecimalFormat.parse(Unknown Source)

          at java.text.SimpleDateFormat.subParse(Unknown Source)

          at java.text.SimpleDateFormat.parse(Unknown Source)

          at java.text.DateFormat.parse(Unknown Source)

          at com.leisure.DateUtil.parse(DateUtil.java:12)

          at com.leisure.TestSimpleDateFormatThreadSafe.run(TestSimpleDateFormatThreadSafe.java:16)

          Fri Dec 23 19:02:20 CST 2011

          Fri Dec 23 18:02:20 CST 2011

          輸出結(jié)果很明顯了,跟線上數(shù)據(jù)出現(xiàn)的問題基本一致。不過按照這里看到的結(jié)果,有報錯,再仔細閱讀了應(yīng)用的底層代碼,
          某個位置攔截了部份異常,沒有記錄也沒有向上拋出處理,到這里,我只想問一句:底層代碼誰寫的?

          posted on 2011-10-15 00:22 leisure 閱讀(2879) 評論(0)  編輯  收藏 所屬分類: java

          主站蜘蛛池模板: 深泽县| 灌云县| 彰化县| 铜陵市| 永平县| 河池市| 临颍县| 曲水县| 盈江县| 循化| 朝阳区| 莱阳市| 百色市| 浮山县| 邢台市| 读书| 汉沽区| 阿瓦提县| 秦皇岛市| 陇川县| 九龙县| 游戏| 安龙县| 札达县| 洱源县| 郴州市| 通河县| 长治市| 广南县| 开原市| 道孚县| 柳林县| 耒阳市| 西盟| 兴化市| 昌宁县| 成安县| 徐州市| 都匀市| 南充市| 搜索|