懶漢式單例模式–雙重檢查鎖
public final class Singleton {
private Singleton() { }
private static volatile Singleton INSTANCE = null;
public static Singleton getInstance() {
// 執行個體沒建立,才會進入内部的 synchronized代碼塊
if (INSTANCE == null) {
synchronized (Singleton.class) { // t2
// 也許有其它線程已經建立執行個體,是以再判斷一次
if (INSTANCE == null) { // t1
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
要點:
- volatile:可見性、有序性
- static:靜态的(懶漢式)
- synchronized:原子性、可見性、有序性
- 雙重檢查:兩個 if 判斷
實作特點:
- 懶惰執行個體化(static)
- 首次使用 getInstance() 才使用 synchronized 加鎖,後續使用時無需加鎖
讀寫 volatile 變量時會加入記憶體屏障(Memory Barrier(Memory Fence)),保證下面兩點:
- 可見性
- 寫屏障(sfence)保證在該屏障之前的 t1 對共享變量的改動,都同步到主存當中
- 而讀屏障(lfence)保證在該屏障之後 t2 對共享變量的讀取,加載的是主存中最新資料
- 有序性
- 寫屏障會確定指令重排序時,不會将寫屏障之前的代碼排在寫屏障之後
- 讀屏障會確定指令重排序時,不會将讀屏障之後的代碼排在讀屏障之前
- 更底層是讀寫變量時使用 lock 指令來多核 CPU 之間的可見性與有序性