由源码能够知道,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.使用同步锁测试