类simpleDateFormat主要负责日期的转换和格式化,但在多线程的环境中,使用此内容容易造成数据转换以及处理的不准确,
因为simpleDateFormat类并不是线程安全的。
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 { // dateString 传入的日期字符串 Date dateRef = sdf.parse(dateString); // newDateString 根据传入的字符串转换成日期,然后,在转换后的字符串 String newDateString= sdf.format(dateRef).toString(); if(!newDateString.equals(dateString)){ System.out.println("ThreadName="+this.getName() +"报错了 日期字符串:"+dateString+" 转换成的日期为:"+newDateString); } } catch (ParseException e) { e.printStackTrace(); } } }
测试,以及结果
public class Test { public static void main(String[] args) { SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); String[] dateStringArray=new String[]{ "2001-01-01","2000-01-02","2000-01-03", "2001-01-04","2000-01-05","2000-01-06", "2001-01-07","2000-01-08","2000-01-09","2000-01-10" }; MyThread[] threadArray=new MyThread[10]; for (int i = 0; i < 10; i++) { threadArray[i]=new MyThread(sdf,dateStringArray[i]); } for (int i = 0; i < 10; i++) { threadArray[i].start(); } } } ThreadName=Thread-1报错了 日期字符串:2000-01-02 转换成的日期为:1970-01-01 ThreadName=Thread-4报错了 日期字符串:2000-01-05 转换成的日期为:1970-01-01 ThreadName=Thread-3报错了 日期字符串:2001-01-04 转换成的日期为:1970-01-01 ThreadName=Thread-2报错了 日期字符串:2000-01-03 转换成的日期为:2000-01-01
使用单例的simpleDateFormat类在多线程的环境中处理,容易出错。
解决方法一
public class DateTools { // 经过字符串转换成指定格式的日期 public static Date parse(String formatPattern, String dateString) throws ParseException { return new SimpleDateFormat(formatPattern).parse(dateString); } // 将日期转换成指定的格式的字符串 public static String format(String formatPattern,Date date) { return new SimpleDateFormat(formatPattern).format(date).toString(); } }
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 { // dateString 传入的日期字符串 Date dateRef = DateTools.parse("yyyy-MM-dd",dateString); // newDateString 根据传入的字符串转换成日期,然后,在转换后的字符串 String newDateString= DateTools.format("yyyy-MM-dd",dateRef); if(!newDateString.equals(dateString)){ System.out.println("ThreadName="+this.getName() +"报错了 日期字符串:"+dateString+" 转换成的日期为:"+newDateString); }else{ System.out.println("ThreadName="+this.getName() +" 日期字符串:"+dateString+" 转换成的日期为:"+newDateString); } } catch (ParseException e) { e.printStackTrace(); } } }
没有任何异常,解决处理错误的原理其实就是创建多个simpleDateFormat类的实例;
解决方法二
threadlocal类能使线程绑定到指定的对象。
public class DateTools { // ThreadLocal相当于一个map,key为线程的标识,value为每个线程设置的value private static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<>(); public static SimpleDateFormat getSimpleDateFormat(String datePattern) { SimpleDateFormat sdf = null; sdf = t1.get(); if (sdf == null) { sdf = new SimpleDateFormat(datePattern); t1.set(sdf); } return sdf; } }
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 { // dateString 传入的日期字符串 Date dateRef = DateTools.getSimpleDateFormat("yyyy-MM-dd").parse(dateString); // newDateString 根据传入的字符串转换成日期,然后,在转换后的字符串 String newDateString= DateTools.getSimpleDateFormat("yyyy-MM-dd").format(dateRef).toString(); if(!newDateString.equals(dateString)){ System.out.println("ThreadName="+this.getName() +"报错了 日期字符串:"+dateString+" 转换成的日期为:"+newDateString); }else{ System.out.println("ThreadName="+this.getName() +" 日期字符串:"+dateString+" 转换成的日期为:"+newDateString); } } catch (ParseException e) { e.printStackTrace(); } } }
这种结果没有异常。