Java?SimpleDateFormat線程不安全問題
多線程 ——SimpleDateFormat
public class DateTest {
//工具類中的日期組件
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) throws Exception {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(10));
for (int i = 0; i < 100; i++) {
threadPoolExecutor.execute(() -> {
String dateString = sdf.format(new Date());
try {
Date parseDate = sdf.parse(dateString);
String dateString2 = sdf.format(parseDate);
System.out.println(dateString.equals(dateString2));
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
}
結果

原因分析
全局變量的SimpleDateFormat,在并發(fā)情況下,存在安全性問題。
我們通過源碼看下:
SimpleDateFormat繼承了 DateFormat

DateFormat類中維護了一個全局的Calendar變量

sdf.parse(dateStr)和sdf.format(date),都是由Calendar引用來儲存的。
如果SimpleDateFormat是static全局共享的,Calendar引用也會被共享。
又因為Calendar內(nèi)部并沒有線程安全機制,所以全局共享的SimpleDateFormat不是線性安全的。
解決方法
解決方法1
「FastDateFormat(FastDateFormat能保證線程安全) 替換 SimpleDateFormat」
private static final FastDateFormat sdf = FastDateFormat.getInstance(“yyyy-MM-dd HH:mm:ss”);
測試代碼如下所示:
public class DateTest {
//工具類中的日期組件
// private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static final FastDateFormat sdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) throws Exception {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(10));
for (int i = 0; i < 100; i++) {
threadPoolExecutor.execute(() -> {
String dateString = sdf.format(new Date());
try {
Date parseDate = sdf.parse(dateString);
String dateString2 = sdf.format(parseDate);
System.out.println(dateString.equals(dateString2));
} catch (Exception e) {
e.printStackTrace();
}
});
}
threadPoolExecutor.shutdown();
}
}
打印結果:

解決方法2
「使用DateTimeFormatter(DateTimeFormatter是線程安全的,java 8+支持)代替SimpleDateFormat」
private static DateTimeFormatter sdf = DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”);
測試代碼如下:
public class DateTest {
//工具類中的日期組件
// private static final SimpleDateFormat sdf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
private static DateTimeFormatter sdf = DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”);
// private static final FastDateFormat sdf = FastDateFormat.getInstance(“yyyy-MM-dd HH:mm:ss”);
public static void main(String[] args) throws Exception {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(10));
for (int i = 0; i < 100; i++) {
threadPoolExecutor.execute(() -> {
try {
String dateString = sdf.format(LocalDateTime.now());
TemporalAccessor temporalAccessor = sdf.parse(dateString);
String dateString2 = sdf.format(temporalAccessor);
System.out.println(dateString.equals(dateString2));
} catch (Exception e) {
e.printStackTrace();
}
});
}
threadPoolExecutor.shutdown();
}
}
打印結果如下:

總結
在多線程中使用全局變量時一定要考慮到線程安全問題,若不確定是否存在線程安全問題的公共變量,則不要冒然使用,可以做一些測試和資料分析,或者使用局部變量。
到此這篇關于Java SimpleDateFormat線程不安全問題的文章就介紹到這了,更多相關SimpleDateFormat線程不安全內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java啟動時自定義配置文件路徑,自定義log4j2.xml位置方式
這篇文章主要介紹了java啟動時自定義配置文件路徑,自定義log4j2.xml位置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
Java實現(xiàn)數(shù)據(jù)脫敏(Desensitization)的操作指南
數(shù)據(jù)脫敏是指通過對敏感數(shù)據(jù)進行部分或完全隱藏處理,保護敏感信息在存儲和使用過程中的安全性,常見的應用場景包括日志記錄、接口返回、報表展示、數(shù)據(jù)分析等,本文給大家介紹了Java實現(xiàn)數(shù)據(jù)脫敏(Desensitization)的操作指南,需要的朋友可以參考下2025-02-02
用C++實現(xiàn)求N!中末尾0的個數(shù)的方法詳解
這篇文章主要介紹了用C++實現(xiàn)求N!中末尾0的個數(shù)的方法詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-07-07
SpringCloud服務接口調(diào)用OpenFeign及使用詳解
這篇文章主要介紹了SpringCloud服務接口調(diào)用——OpenFeign,在學習Ribbon時,服務間調(diào)用使用的是RestTemplate+Ribbon實現(xiàn),而Feign在此基礎上繼續(xù)進行了封裝,使服務間調(diào)用變得更加方便,需要的朋友可以參考下2023-04-04
解決JPA?save()方法null值覆蓋掉mysql預設的默認值問題
這篇文章主要介紹了解決JPA?save()方法null值覆蓋掉mysql預設的默認值問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11

