Java基礎(chǔ)之單例模式

單例模式,是一種常用的軟件設(shè)計(jì)模式。在它的核心結(jié)構(gòu)中只包含一個(gè)被稱為單例的特殊類。通過單例模式可以保證系統(tǒng)中,應(yīng)用該模式的類一個(gè)類只有一個(gè)實(shí)例。即一個(gè)類只有一個(gè)對象實(shí)例(百度百科)。

單例的實(shí)現(xiàn)有以下幾種方式:

  • 非延遲加載,也稱餓漢模式,顧名思義類加載后就實(shí)例化對象。
public class Singleton {

    //私有構(gòu)造方法
    private Singleton() {}
    //Final 實(shí)例
    private static final Singleton instance = new Singleton();  
    //靜態(tài)無參get方法
    public static Singleton getInstance() {
        return instance;
    }
}
  • 延遲加載,也稱懶漢模式,等到用到該實(shí)例時(shí)再加載。
public class Singleton {

    //私有構(gòu)造方法
    private Singleton() {}
    //Final 實(shí)例
    private static Singleton instance =null;  
    //靜態(tài)無參get方法
    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    
}

synchronized是必須要加的,否則多線程下會(huì)出問題:

線程1先進(jìn)入getInstance方法,然后在new Singleton()執(zhí)行之前,線程2也進(jìn)入getInstance方法,因?yàn)榫€程1還沒有執(zhí)行new Singleton()操作,固線程2的if(instance == null)判斷也是成立的,因此線程2也new了一個(gè)Singleton對象,這樣單例模式就失效了,因此需要加同步鎖。

  • 雙檢查模式
public class Singleton {

    //私有構(gòu)造方法
    private Singleton() {}
    //聲明
    private static volatile Singleton instance =null;  
    //靜態(tài)無參get方法
    public static Singleton getInstance() {
        if(instance == null) {//1
            synchronized (Singleton.class) {
                if(instance == null) {//2
                    instance = new Singleton();//3
                }
            }
        }
        return instance;
    }
    
}

Singleton一定要加volatile修飾,否則同樣在多線程下出問題:

線程1先進(jìn)入getInstance()方法,執(zhí)行到//3處時(shí),線程2進(jìn)入getInstance(),此時(shí)線程1并未初始化完全instance對象(instance = new Singleton()并非是原子操作,第一步為instance分配內(nèi)存,此時(shí)instance已不再為null,第二步調(diào)用其構(gòu)造方法實(shí)例化instance),然而線程2在//1處判斷到instance不為空,則直接返回了未初始化完全的instance對象,故而導(dǎo)致系統(tǒng)崩潰。

  • 使用ThreadLocal修復(fù)雙重檢測
public class Singleton {
    
    private static final ThreadLocal<Singleton> threadLocalSingleton = new ThreadLocal<Singleton>();
    private static Singleton singleton;

    private Singleton() {}

    public static Singleton getInstance() {
        // 每個(gè)線程第一次都會(huì)是null
        if (threadLocalSingleton.get() == null) {
            createInstance();
        }
        return singleton;
    }

    private static final void createInstance() {
        synchronized (Singleton.class) {
            if (singleton == null) {
                singleton = new Singleton();
            }
        }
        //標(biāo)記當(dāng)前線程已初始化過singleton對象
        threadLocalSingleton.set(singleton);
    }

}
  • 內(nèi)部類模式

參考: 單例模式與雙重檢測
更多關(guān)于volatile的知識,請看另一篇文章Java基礎(chǔ)之volatile

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容