雙重校驗鎖實現單例模式:
public class Singleton {
//採用volatile修飾
private volatile static Singleton singleton;
//構造方法私有化
private Singleton(){}
//雙重校驗鎖
public static Singleton getInstance(){
//先判斷對象是否已經實例過,沒有實例化過才進入加鎖代碼
if(singleton == null){
//類對象加鎖
synchronized(Singleton.class){
//再次判斷
if (singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
注意:singleton 採用 volatile 修飾是很有必要的,因爲 singleton = new Singleton() 這句話可以分爲三步:
- 爲 singleton 分配內存空間;
- 初始化 singleton;
- 將 singleton 指向分配的內存空間。
但是由於JVM具有指令重排的特性,執行順序有可能變成 1-3-2。 指令重排在單線程下不會出現問題,但是在多線程下會導致一個線程獲得一個未初始化的實例。例如:線程T1執行了1和3,此時T2調用 getInstance() 後發現 singleton 不爲空,因此返回 singleton, 但是此時的 singleton 還沒有被初始化。
使用 volatile 會禁止JVM指令重排,從而保證在多線程下也能正常執行