1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        單例模式簡單復(fù)雜,線程不安全到安全

        共 3315字,需瀏覽 7分鐘

         ·

        2020-11-19 21:26

        點(diǎn)擊上方「藍(lán)字」關(guān)注我們

        0x01 :簡介

        說到單例模式,可以說單例模式是最常見,也是最常用的設(shè)計(jì)模式了。Spring的bean默認(rèn)就是單例的。雖然單例模式是最簡單的設(shè)計(jì)模式,但是在實(shí)現(xiàn)上有多種方式,分別是餓漢式、懶漢式、雙重校驗(yàn)鎖;在線程安全方面有線程不安全的,也有線程相對(duì)安全的??偟膩碚f實(shí)現(xiàn)單例模式有以下一些特點(diǎn):

        1、私有的構(gòu)造方法

        2、內(nèi)部創(chuàng)建一個(gè)私有成員變量

        3、提供一個(gè)公開、靜態(tài)的獲取成員的方法

        類圖


        0x02:餓漢模式

        首先介紹一下最簡單的單例模式(餓漢模式),這種方式在單例類被加載的時(shí)候?qū)嵗?/span>

        public?class?Singleton?{
        ??????//內(nèi)部創(chuàng)建一個(gè)私有成員變量
        ??????private?static?Singleton?instance?=?new?Singleton();;

        ??????private?Singleton()?{
        ???????????//私有的構(gòu)造方法
        ??????}

        ?????public?static?Singleton?getInstance()?{
        ?????????//提供一個(gè)公開、靜態(tài)的獲取成員的方法
        ?????????return?instance;
        ?????}
        ?}

        或者

        public?class?Singleton?{
        ??????
        //內(nèi)部創(chuàng)建一個(gè)私有成員變量
        ??????private?static?Singleton?instance;

        ??????static?{
        ??????????instance?=?new?Singleton();
        ??????}

        ??????private?Singleton()?{
        ???????????//私有的構(gòu)造方法
        ??????}

        ?????public?static?Singleton?getInstance()?{
        ?????????//提供一個(gè)公開、靜態(tài)的獲取成員的方法
        ?????????return?instance;
        ?????}
        ?}

        餓漢模式的缺點(diǎn)在于,如果單例對(duì)象的創(chuàng)建過程比較耗時(shí),那么將會(huì)導(dǎo)致應(yīng)用程序的啟動(dòng)比較慢。


        0x03:懶漢式

        為了克服餓漢模式的缺點(diǎn),將單例對(duì)象的創(chuàng)建過程延后到第一次使用單例對(duì)象時(shí),這種實(shí)現(xiàn)方式被稱為懶漢模式。

        public?class?Singleton?{

        ?????private?static?Singleton?instance;

        ??????private?Singleton()?{
        ??????}

        ??????public?static?Singleton?getInstance()?{
        ??????????if?(instance?==?null)?{
        ??????????????instance?=?new?Singleton();
        ?????????}
        ?????????return?instance;
        ?????}
        ?}

        需要注意的是懶漢式是線程不安全的。假設(shè)在單例類被實(shí)例化之前,有兩個(gè)線程同時(shí)在獲取單例對(duì)象,線程A在執(zhí)行完if (instance == null) 后,線程調(diào)度機(jī)制將 CPU 資源分配給線程B,此時(shí)線程B在執(zhí)行?if (instance == null)時(shí)也發(fā)現(xiàn)單例類還沒有被實(shí)例化,這樣就會(huì)導(dǎo)致單例類被實(shí)例化兩次。為了防止這種情況發(fā)生,需要對(duì) getInstance() 方法同步處理。改進(jìn)后的懶漢模式:

        public?class?Singleton?{
        ??????private?static?Singleton?instance;

        ??????private?Singleton()?{
        ??????}

        ??????//?線程安全的懶漢模式
        ??????public?synchronized?static?Singleton?getInstance()?{
        ??????????if?(instance?==?null)?{
        ?????????????instance?=?new?Singleton();
        ?????????}

        ?????????return?instance;
        ?????}
        ?}

        可以使用ReentrantLock對(duì)象進(jìn)行同步處理。改進(jìn)后的懶漢模式實(shí)現(xiàn)方式,每次獲取單例對(duì)象時(shí)都會(huì)加鎖,在多線程情況下會(huì)造成性能損耗。


        0x04:雙重校驗(yàn)鎖(double check)

        雙重校驗(yàn)鎖實(shí)現(xiàn)本質(zhì)也是一種懶漢式,相比懶漢式第2種實(shí)現(xiàn)方式將會(huì)有較大的性能提升。

        public?class?Singleton?{??
        ????
        private?static?Singleton?instance;??

        ????private?final?static?Object?lock?=?new?Object();??

        ????private?Singleton()?{??

        ????}??

        ????public?static?Singleton?getInstance(){??
        ????????if?(instance?==?null)?{??
        ????????????synchronized?(lock?)?{??
        ????????????????if?(instance?==?null)?{??
        ????????????????????instance?=?new?Singleton();??
        ????????????????}??
        ????????????}??
        ????????}??
        ????????return?instance;??
        ????}??
        }

        synchronized同步塊括號(hào)中的鎖定對(duì)象是采用的一個(gè)無關(guān)的Object類實(shí)例,而不是采用this,因?yàn)間etInstance是一個(gè)靜態(tài)方法,在它內(nèi)部不能使用未靜態(tài)的或者未實(shí)例的類對(duì)象,因此也可以這樣實(shí)現(xiàn)

        public?class?Singleton?{
        ??????private?volatile?static?Singleton?instance;

        ??????private?Singleton()?{
        ??????}

        ??????public?static?Singleton?getInstance()?{
        ??????????if?(instance?==?null)?{
        ??????????????synchronized?(Singleton.class)?{
        ?????????????????if?(instance?==?null)?{
        ?????????????????????instance?=?new?Singleton();
        ?????????????????}
        ?????????????}
        ?????????}
        ?????????return?instance;
        ?????}
        ?}

        就算在單例類被實(shí)例化時(shí)有多個(gè)線程,同時(shí)執(zhí)行了if (instance == null)的判斷,但同一時(shí)間點(diǎn)只有一個(gè)線程可以獲得鎖后進(jìn)入臨界區(qū)。通過if (instance == null)判斷的每個(gè)線程會(huì)依次獲得鎖進(jìn)入臨界區(qū),所以進(jìn)入臨界區(qū)后還要再判斷一次單例類是否已被其它線程實(shí)例化,以避免多次實(shí)例化。由于雙重加鎖實(shí)現(xiàn)僅在實(shí)例化單例類時(shí)需要加鎖,所以相較于懶漢式第2種實(shí)現(xiàn)方式會(huì)帶來性能上的提升。另外需要注意的是雙重加鎖要對(duì) instance 域加上 volatile關(guān)鍵字修飾符。由于 synchronized 并不是對(duì) instance 實(shí)例進(jìn)行加鎖(因?yàn)楝F(xiàn)在還并沒有實(shí)例),所以線程在執(zhí)行完?instance = new Singleton();修改 instance 的值后,應(yīng)該將修改后的 instance 立即寫入主存(main memory),而不是暫時(shí)存在寄存器或者高速緩沖區(qū)(caches)中,以保證新的值對(duì)其它線程可見。

        掃碼二維碼

        獲取更多精彩

        Java樂園

        有用!分享+在看?
        瀏覽 21
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            韩国少妇xxxx搡xxxx搡 | 亚洲乱交| 肏屄毛片 | 尻逼毛片 | 一级特黄60分钟免费 | 12一15女人片毛片 | 91视频大香蕉 | 性欧美狂战久久久久久久海边 | 国产91亚洲成人精品观看 | 国产精品高潮呻呤欠久A片 |