原因:在多執行緒環境下,當多個執行緒同時使用相同的SimpleDateFormat物件(如static修飾)的話,如呼叫format方法時,多個執行緒會同時呼叫calender.setTime方法,導致time被別的線程修改,因此線程是不安全的。
本教學操作環境:windows7系統、java8版、DELL G3電腦。
執行緒不安全驗證:##
/** * SimpleDateFormat线程安全测试 * 〈功能详细描述〉 * * @author 17090889 * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class SimpleDateFormatTest { private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000), new MyThreadFactory("SimpleDateFormatTest")); public void test() { while (true) { poolExecutor.execute(new Runnable() { @Override public void run() { String dateString = simpleDateFormat.format(new Date()); try { Date parseDate = simpleDateFormat.parse(dateString); String dateString2 = simpleDateFormat.format(parseDate); System.out.println(dateString.equals(dateString2)); } catch (ParseException e) { e.printStackTrace(); } } }); } }輸出:
true false true true false出現了false,表示執行緒不安全1、format方法
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) { pos.beginIndex = pos.endIndex = 0; return format(date, toAppendTo, pos.getFieldDelegate()); } // Called from Format after creating a FieldDelegate private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) { // Convert input date to time field list calendar.setTime(date); boolean useDateFormatSymbols = useDateFormatSymbols(); for (int i = 0; i < compiledPattern.length; ) { int tag = compiledPattern[i] >>> 8; int count = compiledPattern[i++] & 0xff; if (count == 255) { count = compiledPattern[i++] << 16; count |= compiledPattern[i++]; } switch (tag) { case TAG_QUOTE_ASCII_CHAR: toAppendTo.append((char)count); break; case TAG_QUOTE_CHARS: toAppendTo.append(compiledPattern, i, count); i += count; break; default: subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols); break; } } return toAppendTo; }
protected Calendar calendar;可以看到,多個執行緒之間共享變數calendar,並修改calendar。因此在多執行緒環境下,當多個執行緒同時使用相同的SimpleDateFormat物件(如static修飾)的話,如呼叫format方法時,多個執行緒會同時呼叫calender.setTime方法,導致time被別的執行緒修改,因此線程是不安全的。 此外,parse方法也是執行緒不安全的,parse方法實際呼叫的是CalenderBuilder的establish來進行解析,其方法中主要步驟不是原子操作。
解決方案:
1、將SimpleDateFormat定義成局部變數 2、 加一把執行緒同步鎖定:synchronized(lock) 3、使用ThreadLocal,每個執行緒都有自己的SimpleDateFormat物件副本。如:/** * SimpleDateFormat线程安全测试 * 〈功能详细描述〉 * * @author 17090889 * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class SimpleDateFormatTest { private static final ThreadLocal<SimpleDateFormat> THREAD_LOCAL = new ThreadLocal<SimpleDateFormat>() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } }; // private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000), new MyThreadFactory("SimpleDateFormatTest")); public void test() { while (true) { poolExecutor.execute(new Runnable() { @Override public void run() { SimpleDateFormat simpleDateFormat = THREAD_LOCAL.get(); if (simpleDateFormat == null) { simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } String dateString = simpleDateFormat.format(new Date()); try { Date parseDate = simpleDateFormat.parse(dateString); String dateString2 = simpleDateFormat.format(parseDate); System.out.println(dateString.equals(dateString2)); } catch (ParseException e) { e.printStackTrace(); } finally { local.remove(); } } }); } } }4、使用DateTimeFormatter取代SimpleDateFormat DateTimeFormatter是執行緒安全的,預設提供了許多格式化方法,也可以透過ofPattern方法來建立自訂格式化方法。 (1)格式化日期範例:
LocalDateTime localDateTime = LocalDateTime.now(); System.out.println(localDateTime); // 2019-11-20T15:04:29.017 DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); String strDate=localDateTime.format(dtf); System.out.println(strDate); // 2019/23/20 15:23:46(2)解析日期
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); LocalDateTime localDateTime=LocalDateTime.parse("2019/11/20 15:23:46",dtf); System.out.println(localDateTime); // 2019-11-20T15:23:46相關影片教學建議:
以上是simpledateformat線程為什麼不安全的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本文討論了各種Java垃圾收集算法(串行,並行,CMS,G1,ZGC),它們的性能影響和適合大量堆的應用。

本文討論了Java虛擬機(JVM),詳細介紹了其在不同平台運行Java程序中的作用。它說明了JVM的內部流程,密鑰組件,內存管理,垃圾收集和性能Optimizatio

Java的Nashorn Engine可以在Java應用程序中啟用JavaScript腳本。關鍵步驟包括設置Nashorn,管理腳本和優化性能。主要問題涉及安全性,內存管理和未來兼容性

Java的Try-with-Resources通過自動關閉文件流或數據庫連接等資源來簡化資源管理,從而提高代碼可讀性和可維護性。

Java枚舉代表固定的值集,通過自定義方法和構造函數提供類型安全性,可讀性和其他功能。它們增強了代碼組織,可用於開關語句中以進行有效的價值處理。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

記事本++7.3.1
好用且免費的程式碼編輯器

Atom編輯器mac版下載
最受歡迎的的開源編輯器