類SimpleDateFormat主要負責日期的轉換與格式化,但在多線程的環境中,使用此類容易形成數據轉換及處理的不正確,由於SimpleDateFormat並非線程安全的,咱們看一段代碼:java
package chapter7.testsimpledateformat; import java.text.SimpleDateFormat; import java.util.Date; public class MyThread extends Thread{ private SimpleDateFormat sdf; private String dateString; public MyThread(SimpleDateFormat sdf,String dateString) { this.sdf = sdf; this.dateString = dateString; } @Override public void run() { try { super.run(); Date dateRef = sdf.parse(dateString); String newDateStr = sdf.format(dateRef).toString(); if(!newDateStr.equals(dateString)) { System.out.println("ThreadName="+this.getName()+"報錯了 日期字符串:"+dateString+" 轉換成的日期爲:"+newDateStr); } } catch (Exception e) { e.printStackTrace(); } } }
package chapter7.testsimpledateformat; import java.text.SimpleDateFormat; public class Test { public static void main(String[] args) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String[] dateStr = new String[] {"2000-01-01","2000-01-02","2000-01-03","2000-01-04","2000-01-05","2000-01-06","2000-01-07","2000-01-08","2000-01-09","2000-01-10"}; MyThread[] threads = new MyThread[10]; for(int i=0;i<10;i++) { threads[i] = new MyThread(sdf, dateStr[i]); } for(int i=0;i<10;i++) { threads[i].start(); } } }
運行結果:安全
ThreadName=Thread-5報錯了 日期字符串:2000-01-06 轉換成的日期爲:2000-01-02
ThreadName=Thread-6報錯了 日期字符串:2000-01-07 轉換成的日期爲:2000-01-01
ThreadName=Thread-2報錯了 日期字符串:2000-01-03 轉換成的日期爲:2000-01-05
ThreadName=Thread-3報錯了 日期字符串:2000-01-04 轉換成的日期爲:0010-01-10
ThreadName=Thread-4報錯了 日期字符串:2000-01-05 轉換成的日期爲:2000-01-10多線程
解決辦法1:ide
package chapter7.testsimpledateformat; import java.util.Date; public class MyThread extends Thread{ private String dateString; public MyThread(String dateString) { this.dateString = dateString; } @Override public void run() { try { super.run(); Date dateRef = DateTools.parse(dateString); String newDateStr = DateTools.format(dateRef); if(!newDateStr.equals(dateString)) { System.out.println("ThreadName="+this.getName()+"報錯了 日期字符串:"+dateString+" 轉換成的日期爲:"+newDateStr); } } catch (Exception e) { e.printStackTrace(); } } }
package chapter7.testsimpledateformat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class DateTools { private static final String DATE_FORMAT = "yyyy-MM-dd"; public static Date parse(String dateStr) throws ParseException { return new SimpleDateFormat(DATE_FORMAT).parse(dateStr); } public static String format(Date date){ return new SimpleDateFormat(DATE_FORMAT).format(date); } }
package chapter7.testsimpledateformat; public class Test { public static void main(String[] args) { try { String[] dateStr = new String[] {"2000-01-01","2000-01-02","2000-01-03","2000-01-04","2000-01-05","2000-01-06","2000-01-07","2000-01-08","2000-01-09","2000-01-10"}; MyThread[] threads = new MyThread[10]; for(int i=0;i<10;i++) { threads[i] = new MyThread(dateStr[i]); } for(int i=0;i<10;i++) { threads[i].start(); } } catch (Exception e) { e.printStackTrace(); } } }
運行結果:沒有打印錯誤,說明問題解決,解決處理錯誤的原理其實就是建立多個SimpleDateFormat。this
解決方法2:線程
package chapter7.testsimpledateformat; import java.util.Date; public class MyThread extends Thread{ private String dateString; public MyThread(String dateString) { this.dateString = dateString; } @Override public void run() { try { super.run(); Date dateRef = DateTools.getSimpleDateFormat().parse(dateString); String newDateStr = DateTools.getSimpleDateFormat().format(dateRef); if(!newDateStr.equals(dateString)) { System.out.println("ThreadName="+this.getName()+"報錯了 日期字符串:"+dateString+" 轉換成的日期爲:"+newDateStr); } } catch (Exception e) { e.printStackTrace(); } } }
package chapter7.testsimpledateformat; import java.text.SimpleDateFormat; public class DateTools { private static final String DATE_FORMAT = "yyyy-MM-dd"; private static ThreadLocal<SimpleDateFormat> tlLocal = new ThreadLocal<SimpleDateFormat>(); public static SimpleDateFormat getSimpleDateFormat() { SimpleDateFormat sdf = null; sdf = tlLocal.get(); if(sdf == null) { sdf = new SimpleDateFormat(DATE_FORMAT); tlLocal.set(sdf); } return sdf; } }
運行結果:沒有輸出錯誤,說明用ThreadLocal能夠解決問題,ThreadLocal類能使線程綁定到指定的對象。orm