今天有同事说SimpleDateFormat不是线程安全的,于是我做了试验
1 public class TestSimpleDateFormat 2 { 3 final static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); 4 5 public static void main(String[] args) { 6 7 int NUMBER_OF_THREADS = 1000; 8 9 for( int i = 0; i < NUMBER_OF_THREADS ; i++ ) {10 TimeCalc tc = new TimeCalc("20151212",i);11 tc.start();12 }13 }14 15 static class TimeCalc extends Thread {16 private String date;17 public String getDate() {18 return date;19 }20 public TimeCalc(String date, int index) {21 this.date = date;22 }23 24 @Override25 public void run() {26 27 try {28 29 Date parsedDate = null;30 // synchronized(sdf) { 31 parsedDate = sdf.parse(date);32 // }33 System.out.println(parsedDate);34 } catch (ParseException e) {35 e.printStackTrace();36 } catch (Exception e) {37 e.printStackTrace();38 } 39 }40 41 }42 }
我会收到下面如下两种异常,
- java.lang.NumberFormatException: For input string: ""
- java.lang.NumberFormatException: multiple points
去掉30行和32行的注释,一切运行正常。
另外,我也试过org.apache.commons.lang3.time.FastDateParser,这个类也是线程安全的。不过这个类没有public的构造器和静态的工厂方法,只有一个protected的构造函数,看来唯一使用它的方法就是自己动手做一个它的子类,然后给出静态的工厂方法。经测试,在多线程下,没有错误。
1 static class MyDateParser extends FastDateParser { 2 3 protected MyDateParser(String arg0, TimeZone arg1, Locale arg2, 4 Date arg3) { 5 super(arg0, arg1, arg2, arg3); 6 } 7 8 public static MyDateParser getDateParser( String pattern ) { 9 return new MyDateParser(pattern, TimeZone.getDefault(), Locale.getDefault(), null);10 }11 12 }
在网上搜索了,还有更好方法,用Joda Time,如果你在用Java 8,java.time下的类应该都是来自于Joda Time。