解釋單例模式中的 雙重鎖為什么是線程不安全的



一丶 雙排序的單例模式代碼如下

public class SingletonSofeLanEx {

/**
* 如果要保證是單例
* 構造函數一定是私有的
*/
private SingletonSofeLanEx() {
//DO SOME SING
}

public static SingletonSofeLanEx instace = null;

//靜態的工程方式,同一時刻只有一個線程訪問
public static SingletonSofeLanEx getInstace() {
if (null == instace) { //#2:B線程 看到instace已經不是null啦,就直接return啦,然而此刻 第三步的 初始化還沒進行,使用這個實例肯定會有
synchronized (SingletonSofeLanEx.class){
if (instace == null){
instace = new SingletonSofeLanEx(); //#1:A線程 執行到指令重排的 第二步也就是3,分配內存
}
}
}
return instace;
}

}

二丶 解釋為什么是線程不安全的
  我來說一下 SingletonSofeLanEx 在CPU當中的工作流程,總共分為三步
   1:memory = allocate() 分配對象內存空間
2:ctorInstance() 初始化對象
3: instace = memory 設置instace分配的內存
 
jvm和cpu優化會指令重排,上面順序會變成1,3,2
單線程環境下,此順序是沒有問題,2,3 前后沒有依賴性
   但是在多線程情況下會有這種情況,具體看#1,#2

三丶 那么如何解決呢,這里的思路是防止重排序,使用 volatile 可防止jvm跟cpu進行重排序指令
    最終代碼

public class SingletonSofeLanEx {

/**
* 如果要保證是單例
* 構造函數一定是私有的
*/
private SingletonSofeLanEx() {
//實力的時候運行一些計算
}

//1:memory = allocate() 分配對象內存空間
//2:ctorInstance() 初始化對象
//3: instace = memory 設置instace分配的內存

//jvm和cpu優化重新指令重排,上面會變成1,3,2
public volatile static SingletonSofeLanEx instace = null;


//靜態的工程方式,同一時刻只有一個線程訪問
public static SingletonSofeLanEx getInstace() {
if (null == instace) { //2:B線程 看到instace已經不是null啦,就直接return啦,然后第三步的 初始化還沒進行
synchronized (SingletonSofeLanEx.class){
if (instace == null){
instace = new SingletonSofeLanEx(); //1:A線程 執行到指令重排的 第二步也就是3,分配內存
}
}
}
return instace;
}

}



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM