SimpleDateFormat线上报了各种各样奇怪的格式转换的错误,通过小的demo来解决这个问题
public static void main(String[] args) {
final DateFormat YYYY_MM_DD_HH_MM_SS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Callable<Date> task = new Callable<Date>() {
public Date call() throws Exception {
return YYYY_MM_DD_HH_MM_SS.parse("2016-12-18 15:00:34");
}
};
// 创建5个线程的线程池
ExecutorService exec = Executors.newFixedThreadPool(5);
List<Future<Date>> results = new ArrayList<Future<Date>>();
for (int i = 0; i < 10; i++) {
results.add(exec.submit(task));
}
exec.shutdown();
// 输出结果
for (Future<Date> result : results) {
try {
System.out.println(result.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
错误如下:
[^2]java.util.concurrent.ExecutionException: java.lang.NumberFormatException: multiple points
Sun Dec 18 15:00:34 CST 2016
Sun Dec 18 15:00:34 CST 2016
Sun Dec 18 15:00:34 CST 2016
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
Sun Dec 18 15:00:34 CST 2016
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at com.lucky.waimai.api.controller.callback.meituan.order.OrderControllerTest.main(OrderControllerTest.java:96)
Caused by: java.lang.NumberFormatException: multiple points
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1110)
at java.lang.Double.parseDouble(Double.java:540)
at java.text.DigitList.getDouble(DigitList.java:168)
at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2088)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
at java.text.DateFormat.parse(DateFormat.java:355)
at com.lucky.waimai.api.controller.callback.meituan.order.OrderControllerTest$1.call(OrderControllerTest.java:82)
at com.lucky.waimai.api.controller.callback.meituan.order.OrderControllerTest1.call(OrderControllerTest.java:79)atjava.util.concurrent.FutureTask.run(FutureTask.java:262)atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)atjava.util.concurrent.ThreadPoolExecutor1.call(OrderControllerTest.java:79)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor1.call(OrderControllerTest.java:79)atjava.util.concurrent.FutureTask.run(FutureTask.java:262)atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)atjava.util.concurrent.ThreadPoolExecutorWorker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
java.util.concurrent.ExecutionException: java.lang.NumberFormatException: multiple points
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
Sun Dec 18 15:00:34 CST 2016
at com.lucky.waimai.api.controller.callback.meituan.order.OrderControllerTest.main(OrderControllerTest.java:96)
Caused by: java.lang.NumberFormatException: multiple points
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1110)
at java.lang.Double.parseDouble(Double.java:540)
at java.text.DigitList.getDouble(DigitList.java:168)
at java.text.DecimalFormat.parse(DecimalFormat.java:1321)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1793)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1455)
at java.text.DateFormat.parse(DateFormat.java:355)
at com.lucky.waimai.api.controller.callback.meituan.order.OrderControllerTest$1.call(OrderControllerTest.java:82)
at com.lucky.waimai.api.controller.callback.meituan.order.OrderControllerTest1.call(OrderControllerTest.java:79)atjava.util.concurrent.FutureTask.run(FutureTask.java:262)atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)atjava.util.concurrent.ThreadPoolExecutor1.call(OrderControllerTest.java:79)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor1.call(OrderControllerTest.java:79)atjava.util.concurrent.FutureTask.run(FutureTask.java:262)atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)atjava.util.concurrent.ThreadPoolExecutorWorker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
java.util.concurrent.ExecutionException: java.lang.NumberFormatException: For input string: “”
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:188)
at com.lucky.waimai.api.controller.callback.meituan.order.OrderControllerTest.main(OrderControllerTest.java:96)
Caused by: 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)
查询资料,SimpleDateFormat是线程非安全的,顾需要对之前代码作出改造:
public static void main(String[] args) {
Callable<Date> task = new Callable<Date>() {
public Date call() throws Exception {
DateFormat YYYY_MM_DD_HH_MM_SS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return YYYY_MM_DD_HH_MM_SS.parse("2016-12-18 15:00:34");
}
};
// 创建5个线程的线程池
ExecutorService exec = Executors.newFixedThreadPool(5);
List<Future<Date>> results = new ArrayList<Future<Date>>();
for (int i = 0; i < 10; i++) {
results.add(exec.submit(task));
}
exec.shutdown();
// 输出结果
for (Future<Date> result : results) {
try {
System.out.println(result.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
运行结果如下:
实质上就是每次在线程开始时都要去初始化SimpleDateFormat,这样每个线程单独分配空间,就可以避免线程非安全问题。
format方法为什么不线程安全
1.有一个共享变量calendar,而这个共享变量的访问没有做到线程安全
2.当使用format方法时,实际是给calent共享变量设置date值,然后调用subFormat将date转化成字符串
解决此类问题还可以有更多的办法,提供如下,工大家自己实践:
1.创建一个共享的SimpleDateFormat实例变量,但是在使用的时候,需要对这个变量进行同步
2.使用ThreadLocal为每个线程都创建一个线程独享SimpleDateFormat变量
3.需要的时候创建局部变量