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.OrderControllerTestWorker.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.OrderControllerTestWorker.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.需要的時候創建局部變量