1.多線程環(huán)境下SimpleDateFormat的不安全問(wèn)題:
SimpleDateFormat的format方法實(shí)際操作的就是Calendar(Calendar變量也就是一個(gè)共享變量線程不安全)。
也正是因?yàn)槊看卧谵D(zhuǎn)化時(shí)間的時(shí)候foramat會(huì)先把時(shí)間set到calendar中,這樣就會(huì)導(dǎo)致A線程讀取到B線程的時(shí)間

image

image
我們來(lái)試一下:
定義兩個(gè)全局常量
private static final String myDateStr = "2022-01-01";
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
//寫一個(gè)測(cè)試方法:
private static void test(Callable task) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Future future = pool.submit(task);
list.add(future);
}
for (Future future : list) {
System.out.println(future.get());
}
pool.shutdown();
}
//開(kāi)始測(cè)試:
public static void main(String[] args) throws Exception {
test(()->dateFormat.parse(myDateStr));
}
果然控制臺(tái)報(bào)錯(cuò)!

image
解決辦法:
1.每次使用parse直接new一個(gè)SimpleDateFormat
public static void main(String[] args) throws Exception {
test(()->new SimpleDateFormat("yyyy-MM-dd").parse(myDateStr));
}
打印正常!
2.使用synchronized同步鎖
public static void main(String[] args) throws Exception {
test(()->{ synchronized(dateFormat) { return dateFormat.parse(myDateStr);} });
}
打印正常!
3.使用TreadLocal
private static final ThreadLocal<SimpleDateFormat> df = ThreadLocal.withInitial(() ->new SimpleDateFormat("yyyy-MM-dd"));
public static Date parseToDate(String dateString) {
try {
return df.get().parse(dateString);
} catch (ParseException e) {
return null;
}
}
public static void main(String[] args) throws Exception {
test(()->parseToDate(myDateStr));
}
打印正常!
4.使用java8 DateTimeFormatter線程安全對(duì)象
public static void main(String[] args) throws Exception {
test(()->LocalDate.parse(myDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
打印正常!