一、测试
测试代码如下:
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static void main(String[] args) throws ParseException{ for (int i = 0; i < 2; i++) { Thread t = new Thread(new TestRunnable(), "t-" + i); t.start(); } } static class TestRunnable implements Runnable { @Override public void run() { while(true) { long dateTime = 0; String dateStr = "2016-05-09 08:21:02"; try{ Date dt = sdf.parse(dateStr); dateTime = dt.getTime(); } catch(Exception e){ e.printStackTrace(); } if(dateTime < 0) { System.out.println(dateTime); } } } }
输出结果:
java.lang.NumberFormatException: For input string: "" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Long.parseLong(Long.java:453) at java.lang.Long.parseLong(Long.java:483) at java.text.DigitList.getLong(DigitList.java:194) at java.text.DecimalFormat.parse(DecimalFormat.java:1316) at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2088) at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455) at java.text.DateFormat.parse(DateFormat.java:355)-125744830738000-61916917138000-61916917138000 at com.tiza.ngp.rp.sanhui.util.Utils$TestRunnable.run(Utils.java:214) at java.lang.Thread.run(Thread.java:745)java.lang.NumberFormatException: For input string: "" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Long.parseLong(Long.java:453)
结果要么抛异常,要么结果为错误的负值。
二、简单分析
public abstract class DateFormat extends Format { /** * The {@link Calendar} instance used for calculating the date-time fields * and the instant of time. This field is used for both formatting and * parsing. * *Subclasses should initialize this field to a {@link Calendar} * appropriate for the {@link Locale} associated with this *
DateFormat
. * @serial */ protected Calendar calendar; ...}
DateFormat类使用了Calendar对象来维护parse和format过程中的日期时间值,当多线程同时使用同一个DateFormat对象,也就是多线程同时使用同一个Calendar对象来维护parse或format过程的日期时间值,必定会发生错乱。
引用Java api文档:
Synchronization
Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.
三、解决方案
使用中要么为每个线程创建一个DateFormat实例,要么对其外部加锁。