單例模式之雙重檢測鎖


  先來看看雙重檢測鎖的實現以及一些簡要的說明(本文主要說明雙重檢測鎖帶來的線程安全問題):

  

/**
 * 單例模式之雙檢鎖
 * @author ring2
 * 懶漢式升級版
 */
public class Singleton3 {

    private static volatile Singleton3 instance;
    
    private Singleton3() {}
    
    public static Singleton3 getInstance() {
        
        //首先判斷是否為空
        if(instance==null) {
            //可能多個線程同時進入到這一步進行阻塞等待
            synchronized(Singleton3.class) {
                //第一個線程拿到鎖,判斷不為空進入下一步
                if(instance==null) {
                    /**
                     * 由於編譯器的優化、JVM的優化、操作系統處理器的優化,可能會導致指令重排(happen-before規則下的指令重排,執行結果不變,指令順序優化排列)
                     * new Singleton3()這條語句大致會有這三個步驟:
                     * 1.在堆中開辟對象所需空間,分配內存地址
                     * 2.根據類加載的初始化順序進行初始化
                     * 3.將內存地址返回給棧中的引用變量
                     * 
                     * 但是由於指令重排的出現,這三條指令執行順序會被打亂,可能導致3的順序和2調換
                     * 👇
                     */
                    instance = new Singleton3();
                }
            }
        }
        return instance;
    }
}

  由於指令重排導致3,2的順序調換以及處於多線程場景,會導致以下問題的出現首先第一個線程執行到了3號指令(instance變量被分配了地址,不為null了),但對象未初始化。此時!第一個或者第二個if語句進行判斷時結果為true,自然而然在使用instance時會出錯。

  解決的方法便是在instance變量上加上volatile關鍵字,加上volatile關鍵字后會禁止該變量的指令重排,從而達到線程安全。關於volatile關鍵字。。。又可以說上一篇。在其他篇章。


免責聲明!

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



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