由源碼能夠知道,SimpleDateFormat 類的數據時保存在類中的,若是咱們在本身的類開始就聲明public static final SimpleDateFormat SDF = new SimpleDateFormat("MMdd");的話,那麼SimpleDateFormat 內部數據就會混亂。出現日期轉換錯誤。java
使用單元測試,在多線程中對兩個日期操做,當只剩下最後一個線程的時候,錯誤不會再出現。多線程
package com.ch.dcs.sync.core.test; import org.junit.Test; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Random; import java.util.concurrent.atomic.AtomicLong; /** * Created by 002387 on 2017/2/3. */ public class DateFormatTest { public static final SimpleDateFormat SDF = new SimpleDateFormat("MMdd"); @Test public void test1(){ Calendar c = Calendar.getInstance(); Date d1 = c.getTime(); c.add(Calendar.DATE, -3); Date d2 = c.getTime(); final String s1 = SDF.format(d1); final String s2 = SDF.format(d2); System.out.println(String.format("test date %s and %s", s1, s2)); final Random ran = new Random(); final AtomicLong count = new AtomicLong(0); for (int i = 0; i < 3; i++) { new Thread() { @Override public void run() { for (;;) { count.addAndGet(1); boolean flag = ran.nextBoolean(); Date d = flag ? d1 : d2; String s = flag ? s1 : s2; String r = SDF.format(d); if(!s.equals(r)){ System.out.println(String.format("== count %s date %s format to %s", count.get(), d.toString(), r)); throw new RuntimeException(""); } else { // System.out.println(String.format("thread %s date %s format to %s", Thread.currentThread(), d.toString(), r)); } } } }.start(); } try { Thread.sleep(Long.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } } }
會拋出RuntimeException異常,當線程數只剩下一的時候,異常消失,同時數據也不會出現錯誤, 結果:dom
test date 0203 and 0131 == count 21 date Fri Feb 03 16:16:12 CST 2017 format to 0231 == count 50 date Fri Feb 03 16:16:12 CST 2017 format to 0231 Exception in thread "Thread-0" java.lang.RuntimeException: at com.ch.dcs.sync.core.test.DateFormatTest$1.run(DateFormatTest.java:41) Exception in thread "Thread-2" java.lang.RuntimeException: at com.ch.dcs.sync.core.test.DateFormatTest$1.run(DateFormatTest.java:41) Process finished with exit code 1
###解決辦法ide
1.使用局部變量,每一個線程中聲明本身的對象,可是消耗太大,不可取。 2.使用 ThreadLocal,這裏每一個線程將有它本身的 SimpleDateFormat 副本。單元測試
private static final ThreadLocal<DateFormat> FORMAT = new ThreadLocal<DateFormat>(){ @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyyMMddHHmmss"); } }; //獲取對象的時候使用get()方法以下 ORMAT.get().parse("20161010000000");
3.使用同步鎖測試