在這篇文章中,我們將探索在Java 中實作執行緒安全單例的幾種方法,包括熱切初始化、雙重檢查鎖定 和 內部靜態類別 方法。我們也將討論為什麼 Final 關鍵字有利於確保單例的完整性。
當您在整個應用程式中恰好需要類別的一個實例時,單例非常有用。常見用例包括管理共享資源,例如日誌記錄、配置或連線池。單例確保存取一個類別的多個請求共享同一個實例,而不是建立新實例。
急切初始化模式在類別載入時建立單例實例。這很簡單並且確保了線程安全,因為實例是在 JVM 載入類別時建立的。
public final class Singleton { // Instance is created at class loading time private static final Singleton INSTANCE = new Singleton(); // Private constructor prevents instantiation from other classes private Singleton() {} public static Singleton getInstance() { return INSTANCE; } }
優點:
缺點:
何時使用它:當單例類別是輕量級的並且您確定它將在應用程式運行時使用它時,熱切初始化是最好的。
如果您想要延遲建立單例直到需要時(稱為延遲初始化),雙重檢查鎖定提供了一個執行緒安全的解決方案。它使用最少的同步並確保僅在第一次存取實例時才建立實例。
public final class Singleton { // Marked as final to prevent subclassing // volatile ensures visibility and prevents instruction reordering private static volatile Singleton instance; // Private constructor prevents instantiation from other classes private Singleton() {} public static Singleton getInstance() { if (instance == null) { // First check (no locking) synchronized (Singleton.class) { // Locking if (instance == null) { // Second check (with locking) instance = new Singleton(); } } } return instance; } }
第一次檢查:同步區塊之外的 if (instance == null) 檢查允許我們避免每次呼叫 getInstance() 時鎖定。這透過繞過初始化後未來調用的同步塊來提高效能。
同步區塊:一旦實例為空,進入同步區塊可確保只有一個執行緒建立 Singleton 實例。到達這一點的其他線程必須等待,以防止競爭條件。
第二次檢查:在同步區塊內,我們再次檢查實例以確保當前執行緒等待時沒有其他執行緒初始化它。此雙重檢查可確保僅建立一個 Singleton 實例。
可變關鍵字在雙重檢查鎖定模式中至關重要,以防止指令重新排序。如果沒有它,語句instance = new Singleton();在完全初始化之前,其他執行緒可能會顯得已完成,從而導致傳回部分構造的實例。易失性保證一旦實例非空,它就被完全建構並且對所有執行緒可見。
這裡使用final關鍵字來防止子類化。將 Singleton 類別標記為 Final 有兩個主要好處:
防止子類化:將類別設為最終類,我們可以防止其他類別擴展它。這確保了 Singleton 類別只能存在一個實例,因為子類化可能會導致額外的實例,從而破壞單例模式。
訊號不變性:final 明確地向其他開發人員指示單例類別是不可變的,不應擴展。這使得程式碼更容易理解和維護。
簡而言之,final 增強了單例的完整性,並有助於避免子類化所帶來的意外行為。
優點:
缺點:
何時使用它:當單例類別是資源密集且可能不總是需要時,或者當需要考慮多執行緒環境中的效能時,此模式非常有用。
延遲初始化的另一種執行緒安全方法是內部靜態類別模式。這利用了 Java 的類別載入機制,僅在需要時才初始化單例實例,無需明確同步。
public final class Singleton { // Instance is created at class loading time private static final Singleton INSTANCE = new Singleton(); // Private constructor prevents instantiation from other classes private Singleton() {} public static Singleton getInstance() { return INSTANCE; } }
在此模式中,SingletonHelper 類別僅在第一次呼叫 getInstance() 時載入。這會觸發 INSTANCE 的初始化,確保延遲載入而不需要同步區塊。
優點:
缺點:
何時使用它:當您希望使用乾淨、可維護的程式碼進行延遲初始化時,請使用內部靜態類別模式。由於簡單性和線程安全性,這通常是首選。
我們研究了在 Java 中實作執行緒安全單例的三種流行方法:
每種方法都有其優點並適合不同的場景。在您自己的專案中嘗試一下,看看哪一個最適合您!如果您有首選方法或有任何問題,請在評論中告訴我。
編碼愉快! ?????
以上是不要讓你的單身人士崩潰!以下是如何在 Java 中使其線程安全的詳細內容。更多資訊請關注PHP中文網其他相關文章!