SimpleDateFormat非线程不安全
来源:互联网 发布:詹姆斯生涯场均数据 编辑:程序博客网 时间:2024/06/06 01:17
1 单线程环境
类SimpleDateFormate常用于时间格式转换,在单线程环境下运行结果正常,如下所示
public class MyThread extends Thread { private SimpleDateFormatsdf; private StringdateString; publicMyThread(SimpleDateFormatsdf, String dateString) { this.sdf =sdf; this.dateString =dateString; } Public void run() { try { Date date = sdf.parse(dateString); String newDateString = sdf.format(date).toString(); if (!newDateString.equals(dateString)) { System.out.println("日期字符串: " + dateString + "转换成日期为:" +newDateString); } } catch(ParseExceptione) { e.printStackTrace(); } }}
public class SingleThreadTest{ public static void main(String[]args) { SimpleDateFormat sdf = newSimpleDateFormat("yyyy-MM-dd"); String[] dateStringArray = new String[]{"2017-01-01","2017-01-02", "2017-01-03","2017-01-04", "2000-01-05", "2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"}; MyThread[] threadArray = newMyThread[10]; for(inti = 0; i < 10;i++){ threadArray[i] = new MyThread(sdf,dateStringArray[i]); } for(inti = 0; i < 10;i++){ threadArray[i].run(); //单线程情况下 } }}
运行结果:
2 并发环境
在并发环境下,使用类SimpleDateFormate进行日期格式转换会出现数据处理不正确,根本原因是存在共享变量calendar。
public class MutiThreadTest{ public static void main(String[]args) { SimpleDateFormat sdf = newSimpleDateFormat("yyyy-MM-dd"); String[] dateStringArray = new String[]{"2017-01-01","2017-01-02", "2017-01-03","2017-01-04", "2000-01-05", "2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"}; MyThread[] threadArray = newMyThread[10]; for(inti = 0; i < 10;i++){ threadArray[i] = new MyThread(sdf,dateStringArray[i]); } for(inti = 0; i < 10;i++){ threadArray[i].start(); //多线程条件下 } }}
运行结果:
3 解决方法
3.1使用 LocalDate类
JDK8时间新特性类LocalDate是线程安全,而且使用方法更简单
public class Test { public static void main(String[]args) { String[] dateStringArray = new String[]{"2017-01-01","2017-01-02", "2017-01-03","2017-01-04", "2000-01-05", "2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"}; MyThread[] threadArray = newMyThread[10]; for(inti = 0; i < 10;i++){ threadArray[i] = new MyThread(dateStringArray[i]); } for(inti = 0; i < 10;i++){ threadArray[i].start(); //多线程条件下 } }}
public class MyThread extends Thread { private StringdateString; public MyThread(StringdateString) { super(); this.dateString =dateString; } public void run() { LocalDate date = LocalDate.parse(dateString);// JDK8新特性 if (!date.toString().equals(dateString)) { System.out.println("日期字符串: " +dateString + "转换成日期为:" +date); } }}
3.2 使用ThreadLocal类
类ThreadLocal解决的是变量在不同线程间的隔离性,也就是不同线程拥有自己的隔离值,不同线程中的值可以放入ThreadLocal类中进行保存。
public class DateTools{ privatestaticThreadLocal<SimpleDateFormat> t1 = newThreadLocal<SimpleDateFormat>(); publicstaticSimpleDateFormat getSimpleDateFormate(StringdatePattern){ SimpleDateFormat sdf = null; sdf = t1.get(); if(sdf ==null){ sdf = newSimpleDateFormat(datePattern); t1.set(sdf); } returnsdf; }}
public class MyThread extends Thread { private StringdateString; public MyThread(StringdateString) { super(); this.dateString =dateString; } publicvoid run(){ try { Date dateRef =DateTools.getSimpleDateFormate("yyyy-MM-dd").parse(dateString); String newDateString = DateTools.getSimpleDateFormate("yyyy-MM-dd").format(dateRef).toString(); if (!newDateString.equals(dateString)) { System.out.println("日期字符串: " + dateString + "转换成日期为:" +newDateString); } } catch(ParseExceptione) { e.printStackTrace(); } }}
public class Test { publicstatic voidmain(String[]args) { String[] dateStringArray = new String[]{"2017-01-01","2017-01-02", "2017-01-03","2017-01-04", "2000-01-05", "2017-01-06", "2017-01-07", "2017-01-08", "2017-01-09", "2017-01-10"}; MyThread[] threadArray = newMyThread[10]; for(inti = 0; i < 10;i++){ threadArray[i] = newMyThread(dateStringArray[i]); } for(inti = 0; i < 10;i++){ threadArray[i].start(); //多线程条件下 } }}
4 参考文献
[1] 高洪岩, Java多线程编程核心技术. 2015.
[2] Goetz, B.等, Java 并发编程实战. 2012.
[3] https://docs.oracle.com/javase/8/docs/api/index.html
阅读全文