类SimpleDateFormat主要负责日期的格式化和转换,但是在多线程的环境中,使用此类容易造成数据转换和处理不正确,因为SimpleDateFormat类并不是线程安全的。
- 1简单示例,出现异常
package com.test.test4; import java.text.SimpleDateFormat; /** * SimpleDateFormat非线程安全 * Created by admin on 2018/12/18. */ public class Test { public static void main(String[] args) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String[]dataStringArray = new String[]{"2000-01-01","2000-01-02","2000-01-03","2000-01-04","2000-01-05"}; MyThread[] threadArray = new MyThread[5]; for (int i=0;i<5;i++) { threadArray[i] = new MyThread(sdf,dataStringArray[i]); } for (int i=0;i<5;i++) { threadArray[i].start(); } } } package com.test.test4; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by admin on 2018/12/18. */ public class MyThread extends Thread { private SimpleDateFormat sdf; private String dateString; public MyThread(SimpleDateFormat sdf,String dateString){ super(); this.sdf = sdf; this.dateString = dateString; } @Override public void run(){ try { Date dateRef = sdf.parse(dateString); String newDateString = sdf.format(dateRef).toString(); if (!newDateString.equals(dateString)) { System.out.println("ThreadName="+this.getName()+"报错了 日期字符串:"+dateString+"转换成的日期为"+newDateString); } } catch (ParseException e) { e.printStackTrace(); } } }
- 运行结果
ThreadName=Thread-4报错了 日期字符串:2000-01-05转换成的日期为0001-01-02 ThreadName=Thread-2报错了 日期字符串:2000-01-03转换成的日期为0001-01-02 ThreadName=Thread-0报错了 日期字符串:2000-01-01转换成的日期为0001-01-02 ThreadName=Thread-3报错了 日期字符串:2000-01-04转换成的日期为0001-01-02 Process finished with exit code 0
- 解决异常办法一:解决处理错误的原理是创建了多个SimpleDateFormat
public class Test { public static void main(String[] args) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String[]dataStringArray = new String[]{"2000-01-01","2000-01-02","2000-01-03","2000-01-04","2000-01-05"}; MyThread[] threadArray = new MyThread[5]; for (int i=0;i<5;i++) { threadArray[i] = new MyThread(sdf,dataStringArray[i]); } for (int i=0;i<5;i++) { threadArray[i].start(); } } } package com.test.formatOk1; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by admin on 2018/12/18. */ public class DateTools { public static Date parse(String formatPattern, String dataString) throws ParseException{ return new SimpleDateFormat(formatPattern).parse(dataString); } public static String format(String formatPattern,Date date){ return new SimpleDateFormat(formatPattern).format(date).toString(); } } package com.test.formatOk1; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by admin on 2018/12/18. */ public class MyThread extends Thread { private SimpleDateFormat sdf; private String dateString; public MyThread(SimpleDateFormat sdf,String dateString){ super(); this.sdf = sdf; this.dateString = dateString; } @Override public void run(){ try { Date dateRef = DateTools.parse("yyyy-MM-dd",dateString); String newDateString = DateTools.format("yyyy-MM-dd",dateRef).toString(); if (!newDateString.equals(dateString)) { System.out.println("ThreadName="+this.getName()+"报错了 日期字符串:"+dateString+"转换成的日期为"+newDateString); } } catch (ParseException e) { e.printStackTrace(); } } }
解决异常办法二:ThreadLocal类能使线程绑定到指定对象,使用ThreadLocal也可以处理这种错误
package com.test.formatOk2; import java.text.SimpleDateFormat; /** * SimpleDateFormat非线程安全 * Created by admin on 2018/12/18. */ public class Test { public static void main(String[] args) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String[]dataStringArray = new String[]{"2000-01-01","2000-01-02","2000-01-03","2000-01-04","2000-01-05"}; MyThread[] threadArray = new MyThread[5]; for (int i=0;i<5;i++) { threadArray[i] = new MyThread(sdf,dataStringArray[i]); } for (int i=0;i<5;i++) { threadArray[i].start(); } } } package com.test.formatOk2; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by admin on 2018/12/18. */ public class DateTools { private static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<SimpleDateFormat>(); public static SimpleDateFormat getSimpleDateFormat(String datePattern){ SimpleDateFormat sdf = null; sdf = t1.get(); if (sdf == null) { sdf = new SimpleDateFormat(datePattern); t1.set(sdf); } return sdf; } } package com.test.formatOk2; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by admin on 2018/12/18. */ public class MyThread extends Thread { private SimpleDateFormat sdf; private String dateString; public MyThread(SimpleDateFormat sdf,String dateString){ super(); this.sdf = sdf; this.dateString = dateString; } @Override public void run(){ try { Date dateRef = DateTools.getSimpleDateFormat("yyyy-MM-dd").parse(dateString); String newDateString = DateTools.getSimpleDateFormat("yyyy-MM-dd").format(dateRef).toString(); if (!newDateString.equals(dateString)) { System.out.println("ThreadName="+this.getName()+"报错了 日期字符串:"+dateString+"转换成的日期为"+newDateString); } } catch (ParseException e) { e.printStackTrace(); } } }