標籤:機制 on() zed 消極式載入 基礎 初始 多線程 volatil 檢測
目錄
- 餓漢式單例
- 懶漢式單例
- DCL+ volatile
- 靜態內部類實現單例模式
餓漢式單例
public class Singleton { private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; }}
餓漢式單例,在類第一次載入的時候,單例就完成了初始化,是安全執行緒的。
懶漢式單例
public class Singleton { private static Singleton instance = null; public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; }}
懶漢式單例,運用了消極式載入,在需要的時候進行初始化。
但多線程下有兩個問題:
- 可能會得到不同的執行個體,違背了單例的初衷。
- 可能得到一個尚未初始化完全的對象。
怎樣修改懶漢式單例才能保證執行緒安全性呢?
DCL+ volatile
DCL 即雙重檢查鎖定機制
// 嘗試一:鎖可以保證執行緒安全性,但並發的情況下阻塞會導致效率低public class Singleton { private static Singleton instance = null; synchronized public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; }}// 嘗試二:縮小同步塊的範圍,有助於提高效率,但效果微乎其微public class Singleton { private static Singleton instance = null; public static Singleton getInstance() { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } return instance; }}// 嘗試三:繼續縮小同步塊的範圍,效率明顯提升,但得到的可能不是單例public class Singleton { private static Singleton instance = null; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { instance = new Singleton(); } } return instance; }}// 嘗試四:DCL,第一次空值檢測對提升效能起到了很大的作用,但可能得到一個尚未初始化完全的對象public class Singleton { private static Singleton instance = null; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }}// 嘗試五:在 DCL 基礎上,為變數 instance 加上 voltile 關鍵字public class Singleton { private volatile static Singleton instance = null; public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }}
voltile 禁止了指令級並行的《重排序》,保證了初始化安全性。
懶漢式單例,使用 DCL + volatile,才具有執行緒安全性。
靜態內部類實現單例模式
public class Singleton { private static class Holder{ private static Singleton instance = new Singleton(); } public static Singleton getInstance() { return Holder.instance; }}
調用 getInstance 方法導致 Holder 類被載入,載入過程中初始化了單例。
而類的載入是加鎖的,載入完成後才能載入另一個類,因此能夠保證單例模式的安全性。
同時具有延時載入的特性。
單例模式