懶漢式單例模式是指,在全局的單例實例在第一次被使用時構建
用雙重檢查鎖實現線程安全的懶漢式單例模式
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getUniqueInstance() {
//先判斷對象是否已經實例過,沒有實例化過才進入加鎖代碼
if (uniqueInstance == null) {
//類對象加鎖
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
上面的代碼中,創建一個私有的構造方法,避免外部創建類的示例;然後定義一個靜態的類的實例,外部通過getUniqueInstance獲取此靜態示例,以此實現單例;用雙重檢查鎖保證線程安全。
另外,需要注意 uniqueInstance 採用 volatile 關鍵字修飾也是很有必要。
uniqueInstance 採用 volatile 關鍵字修飾也是很有必要的, uniqueInstance = new Singleton(); 這段代碼其實是分爲三步執行:
- 爲 uniqueInstance 分配內存空間
- 初始化 uniqueInstance
- 將 uniqueInstance 指向分配的內存地址
但是由於 JVM 具有指令重排的特性,執行順序有可能變成 1->3->2。指令重排在單線程環境下不會出現問題,但是在多線程環境下會導致一個線程獲得還沒有初始化的實例。例如,線程 T1 執行了 1 和 3,此時 T2 調用 getUniqueInstance() 後發現 uniqueInstance 不爲空,因此返回 uniqueInstance,但此時 uniqueInstance 還未被初始化。
使用 volatile 可以禁止 JVM 的指令重排,保證在多線程環境下也能正常運行。