線程安全的單例模式

懶漢式

加方法鎖

public class Singleton {
    private static Singleton singleton = null;

    private Singleton() {
    }

    public static synchronized Singleton getInstance() {
        if (Objects.isNull(singleton)) {
            singleton = new Singleton();
        }
        return singleton;
    }
}
  1. 直接在 getInstance() 方法加鎖,但是加鎖的范圍太大,性能低下

雙重檢查鎖定

public class Singleton {
    private static volatile Singleton singleton = null;

    private Singleton() {
    }

    public static Singleton getInstance() {
        // 1
        if (Objects.isNull(singleton)) {
            synchronized(Singleton.class) {
                if (Objects.isNull(singleton)) {
                  // 2  
                  singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

對(duì)象需要加volatile 關(guān)鍵字,主要是防止指令重排序。singleton = new Singleton();方法在執(zhí)行的時(shí)候有三個(gè)指令:

memory = allocate();  // 1:分配對(duì)象的內(nèi)存空間
ctorInstance(memory); // 2:初始化對(duì)象
instance = memory;  // 3:設(shè)置instance指向剛分配的內(nèi)存地址

當(dāng)線程A獲取到鎖,執(zhí)行初始化的時(shí)候發(fā)生了指令重排,1->3->2。當(dāng)2還沒有被執(zhí)行時(shí),線程B執(zhí)行到代碼標(biāo)記1的位置,這時(shí)判斷到對(duì)象不為空,直接返回該對(duì)象,但是這個(gè)時(shí)候該對(duì)象可能還并沒有完成初始化,導(dǎo)致線程B在執(zhí)行過程中拋錯(cuò)。

靜態(tài)內(nèi)部類

public class Singleton {
    private static class LazyHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    private Singleton() {
    }

    public static Singleton getInstance() {
        return LazyHolder.INSTANCE;
    }
}

既實(shí)現(xiàn)了線程安全,又避免了同步帶來的性能影響。JVM在類的初始化階段(即在Class被加載后,且被線程使用之前),會(huì)執(zhí)行類的初始化。在 執(zhí)行類的初始化期間,JVM會(huì)去獲取一個(gè)鎖。這個(gè)鎖可以同步多個(gè)線程對(duì)同一個(gè)類的初始化。使用這種方式,我們是允許new Singleton();過程發(fā)生指令重排的。

使用枚舉的形式

public class EnumSingleton {
    private EnumSingleton() {
    }

    public static EnumSingleton getInstance() {
        return Singleton.INSTANCE.getInstance();
    }

    private enum Singleton {
        INSTANCE(new EnumSingleton());
        private EnumSingleton singleton;

        //JVM會(huì)保證此方法絕對(duì)只調(diào)用一次
        Singleton(EnumSingleton singleton) {
            this.singleton = singleton;
        }

        public EnumSingleton getInstance() {
            return singleton;
        }
    }
}

JVM會(huì)保證枚舉類構(gòu)造方法絕對(duì)只調(diào)用一次,所以保證了對(duì)象實(shí)例的唯一性

餓漢式

public class Singleton {
    private static final Singleton singleton = new Singleton();

    private Singleton() {
    }

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

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 很多人比較熟悉單例模式,而且單例涉及的知識(shí)也不少,如果采用同步鎖判斷實(shí)現(xiàn)單例,有如下幾點(diǎn): 利用私有訪問控制...
    MoneyGodChina盛忠閱讀 420評(píng)論 0 0
  • 單例模式作為一種常見的設(shè)計(jì)模式,在程序中非常常見,主要是為了保證一個(gè)類只有一個(gè)唯一的對(duì)象。 從簡(jiǎn)單的“餓漢式”、“...
    Android_大船閱讀 4,170評(píng)論 0 12
  • 轉(zhuǎn)自:http://blog.csdn.net/willamlan/article/details/4859623...
    王帥199207閱讀 135評(píng)論 0 2
  • 簡(jiǎn)介 單例模式是很常用的一種設(shè)計(jì)模式,在實(shí)現(xiàn)過程中要非常注意線程安全,我們會(huì)介紹四種方式來實(shí)現(xiàn)線程安全的單例模式:...
    Kai_Z閱讀 2,451評(píng)論 3 1
  • 阿諾馬上要二十歲了,在這個(gè)寒冷的冬天。她知道不會(huì)有什么人給自己慶祝生日。 阿諾家里沒有過生日的習(xí)慣,父母總是忙于工...
    蘇壹鳴閱讀 690評(píng)論 0 0

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