成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

深入理解單例模式

FuisonDesign / 1195人閱讀

摘要:總結(jié)我們主要介紹到了以下幾種方式實(shí)現(xiàn)單例模式餓漢方式線程安全懶漢式非線程安全和關(guān)鍵字線程安全版本懶漢式雙重檢查加鎖版本枚舉方式參考設(shè)計(jì)模式中文版第二版設(shè)計(jì)模式深入理解單例模式我是一個(gè)以架構(gòu)師為年之內(nèi)目標(biāo)的小小白。

初遇設(shè)計(jì)模式在上個(gè)寒假,當(dāng)時(shí)把每個(gè)設(shè)計(jì)模式過(guò)了一遍,對(duì)設(shè)計(jì)模式有了一個(gè)最初級(jí)的了解。這個(gè)學(xué)期借了幾本設(shè)計(jì)模式的書(shū)籍看,聽(tīng)了老師的設(shè)計(jì)模式課,對(duì)設(shè)計(jì)模式算是有個(gè)更進(jìn)一步的認(rèn)識(shí)。后面可能會(huì)不定期更新一下自己對(duì)于設(shè)計(jì)模式的理解。每個(gè)設(shè)計(jì)模式看似很簡(jiǎn)單,實(shí)則想要在一個(gè)完整的系統(tǒng)中應(yīng)用還是非常非常難的。然后我的水品也非常非常有限,代碼量也不是很多,只能通過(guò)閱讀書(shū)籍、思考別人的編碼經(jīng)驗(yàn)以及結(jié)合自己的編碼過(guò)程中遇到的問(wèn)題來(lái)總結(jié)。

怎么用->怎么用才好->怎么與其他模式結(jié)合使用,我想這是每個(gè)開(kāi)發(fā)人員都需要逾越的一道鴻溝。

本文主要內(nèi)容

1 單例模式簡(jiǎn)介 1.1 定義

保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。

1.2 為什么要用單例模式呢?

在我們的系統(tǒng)中,有一些對(duì)象其實(shí)我們只需要一個(gè),比如說(shuō):線程池、緩存、對(duì)話框、注冊(cè)表、日志對(duì)象、充當(dāng)打印機(jī)、顯卡等設(shè)備驅(qū)動(dòng)程序的對(duì)象。事實(shí)上,這一類對(duì)象只能有一個(gè)實(shí)例,如果制造出多個(gè)實(shí)例就可能會(huì)導(dǎo)致一些問(wèn)題的產(chǎn)生,比如:程序的行為異常、資源使用過(guò)量、或者不一致性的結(jié)果。

簡(jiǎn)單來(lái)說(shuō)使用單例模式可以帶來(lái)下面幾個(gè)好處:

對(duì)于頻繁使用的對(duì)象,可以省略創(chuàng)建對(duì)象所花費(fèi)的時(shí)間,這對(duì)于那些重量級(jí)對(duì)象而言,是非??捎^的一筆系統(tǒng)開(kāi)銷;

由于 new 操作的次數(shù)減少,因而對(duì)系統(tǒng)內(nèi)存的使用頻率也會(huì)降低,這將減輕 GC 壓力,縮短 GC 停頓時(shí)間。

1.3 為什么不使用全局變量確保一個(gè)類只有一個(gè)實(shí)例呢?

我們知道全局變量分為靜態(tài)變量和實(shí)例變量,靜態(tài)變量也可以保證該類的實(shí)例只存在一個(gè)。
只要程序加載了類的字節(jié)碼,不用創(chuàng)建任何實(shí)例對(duì)象,靜態(tài)變量就會(huì)被分配空間,靜態(tài)變量就可以被使用了。

但是,如果說(shuō)這個(gè)對(duì)象非常消耗資源,而且程序某次的執(zhí)行中一直沒(méi)用,這樣就造成了資源的浪費(fèi)。利用單例模式的話,我們就可以實(shí)現(xiàn)在需要使用時(shí)才創(chuàng)建對(duì)象,這樣就避免了不必要的資源浪費(fèi)。 不僅僅是因?yàn)檫@個(gè)原因,在程序中我們要盡量避免全局變量的使用,大量使用全局變量給程序的調(diào)試、維護(hù)等帶來(lái)困難。

2 單例的模式的實(shí)現(xiàn) 通常單例模式在Java語(yǔ)言中,有兩種構(gòu)建方式:

餓漢方式。指全局的單例實(shí)例在類裝載時(shí)構(gòu)建

懶漢方式。指全局的單例實(shí)例在第一次被使用時(shí)構(gòu)建。

不管是那種創(chuàng)建方式,它們通常都存在下面幾點(diǎn)相似處:

單例類必須要有一個(gè) private 訪問(wèn)級(jí)別的構(gòu)造函數(shù),只有這樣,才能確保單例不會(huì)在系統(tǒng)中的其他代碼內(nèi)被實(shí)例化;

instance 成員變量和 uniqueInstance 方法必須是 static 的。

2.1 餓漢方式(線程安全)
    public class Singleton {
       //在靜態(tài)初始化器中創(chuàng)建單例實(shí)例,這段代碼保證了線程安全
        private static Singleton uniqueInstance = new Singleton();
        private Singleton(){}
        public static Singleton getInstance(){
            return uniqueInstance;
        }
    }

所謂 “餓漢方式” 就是說(shuō)JVM在加載這個(gè)類時(shí)就馬上創(chuàng)建此唯一的單例實(shí)例,不管你用不用,先創(chuàng)建了再說(shuō),如果一直沒(méi)有被使用,便浪費(fèi)了空間,典型的空間換時(shí)間,每次調(diào)用的時(shí)候,就不需要再判斷,節(jié)省了運(yùn)行時(shí)間。

## 2.2 懶漢式(非線程安全和synchronized關(guān)鍵字線程安全版本 )

public class Singleton {  
      private static Singleton uniqueInstance;  
      private Singleton (){
      }   
      //沒(méi)有加入synchronized關(guān)鍵字的版本是線程不安全的
      public static Singleton getInstance() {
          //判斷當(dāng)前單例是否已經(jīng)存在,若存在則返回,不存在則再建立單例
          if (uniqueInstance == null) {  
              uniqueInstance = new Singleton();  
          }  
          return uniqueInstance;  
      }  
 }

所謂 “餓漢方式” 就是說(shuō)單例實(shí)例在第一次被使用時(shí)構(gòu)建,而不是在JVM在加載這個(gè)類時(shí)就馬上創(chuàng)建此唯一的單例實(shí)例。

但是上面這種方式很明顯是線程不安全的,如果多個(gè)線程同時(shí)訪問(wèn)getInstance()方法時(shí)就會(huì)出現(xiàn)問(wèn)題。如果想要保證線程安全,一種比較常見(jiàn)的方式就是在getInstance() 方法前加上synchronized關(guān)鍵字,如下:

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

我們知道synchronized關(guān)鍵字偏重量級(jí)鎖。雖然在JavaSE1.6之后synchronized關(guān)鍵字進(jìn)行了主要包括:為了減少獲得鎖和釋放鎖帶來(lái)的性能消耗而引入的偏向鎖和輕量級(jí)鎖以及其它各種優(yōu)化之后執(zhí)行效率有了顯著提升。

但是在程序中每次使用getInstance() 都要經(jīng)過(guò)synchronized加鎖這一層,這難免會(huì)增加getInstance()的方法的時(shí)間消費(fèi),而且還可能會(huì)發(fā)生阻塞。我們下面介紹到的 雙重檢查加鎖版本 就是為了解決這個(gè)問(wèn)題而存在的。

2.3 懶漢式(雙重檢查加鎖版本)

利用雙重檢查加鎖(double-checked locking),首先檢查是否實(shí)例已經(jīng)創(chuàng)建,如果尚未創(chuàng)建,“才”進(jìn)行同步。這樣以來(lái),只有一次同步,這正是我們想要的效果。

public class Singleton {

    //volatile保證,當(dāng)uniqueInstance變量被初始化成Singleton實(shí)例時(shí),多個(gè)線程可以正確處理uniqueInstance變量
    private volatile static Singleton uniqueInstance;
    private Singleton() {
    }
    public static Singleton getInstance() {
       //檢查實(shí)例,如果不存在,就進(jìn)入同步代碼塊
        if (uniqueInstance == null) {
            //只有第一次才徹底執(zhí)行這里的代碼
            synchronized(Singleton.class) {
               //進(jìn)入同步代碼塊后,再檢查一次,如果仍是null,才創(chuàng)建實(shí)例
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

很明顯,這種方式相比于使用synchronized關(guān)鍵字的方法,可以大大減少getInstance() 的時(shí)間消費(fèi)。

我們上面使用到了volatile關(guān)鍵字來(lái)保證數(shù)據(jù)的可見(jiàn)性,關(guān)于volatile關(guān)鍵字的內(nèi)容可以看我的這篇文章:
《Java多線程學(xué)習(xí)(三)volatile關(guān)鍵字》: https://blog.csdn.net/qq_34337272/article/details/79680771

注意: 雙重檢查加鎖版本不適用于1.4及更早版本的Java。
1.4及更早版本的Java中,許多JVM對(duì)于volatile關(guān)鍵字的實(shí)現(xiàn)會(huì)導(dǎo)致雙重檢查加鎖的失效。
2.4 其他方式(枚舉)

除了上面說(shuō)的幾種創(chuàng)建方式之外,還有挺多種其他的創(chuàng)建方式這里稍微多提一點(diǎn)使用枚舉的方式,其他創(chuàng)建方式我們就不管了,沒(méi)有什么實(shí)質(zhì)性的作用。

枚舉實(shí)現(xiàn)單例的優(yōu)點(diǎn)就是簡(jiǎn)單,但是大部分應(yīng)用開(kāi)發(fā)很少用枚舉,可讀性并不是很高。個(gè)人感覺(jué)懶漢式(雙重檢查加鎖版本)還是使用挺多的,這種方式的可讀性也比較好。

public enum Singleton {
     //定義一個(gè)枚舉的元素,它就是 Singleton 的一個(gè)實(shí)例
    INSTANCE;  
    
    public void doSomeThing() {  
         System.out.println("枚舉方法實(shí)現(xiàn)單例");
    }  
}

使用方法:

public class ESTest {

    public static void main(String[] args) {
        Singleton singleton = Singleton.INSTANCE;
        singleton.doSomeThing();//output:枚舉方法實(shí)現(xiàn)單例

    }

}

《Effective Java 中文版 第二版》

這種方法在功能上與公有域方法相近,但是它更加簡(jiǎn)潔,無(wú)償提供了序列化機(jī)制,絕對(duì)防止多次實(shí)例化,即使是在面對(duì)復(fù)雜序列化或者反射攻擊的時(shí)候。雖然這種方法還沒(méi)有廣泛采用,但是單元素的枚舉類型已經(jīng)成為實(shí)現(xiàn)Singleton的最佳方法。 —-《Effective Java 中文版 第二版》

《Java與模式》

《Java與模式》中,作者這樣寫(xiě)道,使用枚舉來(lái)實(shí)現(xiàn)單實(shí)例控制會(huì)更加簡(jiǎn)潔,而且無(wú)償?shù)靥峁┝诵蛄谢瘷C(jī)制,并由JVM從根本上提供保障,絕對(duì)防止多次實(shí)例化,是更簡(jiǎn)潔、高效、安全的實(shí)現(xiàn)單例的方式。
2.5 總結(jié)

我們主要介紹到了以下幾種方式實(shí)現(xiàn)單例模式:

餓漢方式(線程安全)

懶漢式(非線程安全和synchronized關(guān)鍵字線程安全版本)

懶漢式(雙重檢查加鎖版本)

枚舉方式

參考:

《Head First 設(shè)計(jì)模式》

《Effective Java 中文版 第二版》

【Java】設(shè)計(jì)模式:深入理解單例模式

我是Snailclimb,一個(gè)以架構(gòu)師為5年之內(nèi)目標(biāo)的小小白。
歡迎關(guān)注我的微信公眾號(hào):"Java面試通關(guān)手冊(cè)"(一個(gè)有溫度的微信公眾號(hào),期待與你共同進(jìn)步~~~堅(jiān)持原創(chuàng),分享美文,分享各種Java學(xué)習(xí)資源):

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69511.html

相關(guān)文章

  • 深入java單例模式

    摘要:?jiǎn)卫菓?yīng)用開(kāi)發(fā)中一種設(shè)計(jì)模式,主要應(yīng)用場(chǎng)景為當(dāng)且僅當(dāng)系統(tǒng)中只能保留一個(gè)對(duì)象時(shí)使用。本文提出中可以在生產(chǎn)環(huán)境中使用的單例設(shè)計(jì)模式。在的一書(shū)中給出了三種單例設(shè)計(jì)模式采用靜態(tài)變量這種寫(xiě)法使用了私有的構(gòu)造方法。 單例是應(yīng)用開(kāi)發(fā)中一種設(shè)計(jì)模式,主要應(yīng)用場(chǎng)景為:當(dāng)且僅當(dāng)系統(tǒng)中只能保留一個(gè)對(duì)象時(shí)使用。本文提出4中可以在生產(chǎn)環(huán)境中使用的單例設(shè)計(jì)模式。推薦使用enum的方式。 應(yīng)用場(chǎng)景 例如一下應(yīng)用場(chǎng)景...

    Aomine 評(píng)論0 收藏0
  • 求職準(zhǔn)備 - 收藏集 - 掘金

    摘要:一基礎(chǔ)接口的意義百度規(guī)范擴(kuò)展回調(diào)抽象類的意義想不想通過(guò)一線互聯(lián)網(wǎng)公司面試文檔整理為電子書(shū)掘金簡(jiǎn)介谷歌求職記我花了八個(gè)月準(zhǔn)備谷歌面試掘金原文鏈接翻譯者 【面試寶典】從對(duì)象深入分析 Java 中實(shí)例變量和類變量的區(qū)別 - 掘金原創(chuàng)文章,轉(zhuǎn)載請(qǐng)務(wù)必保留原出處為:http://www.54tianzhisheng.cn/... , 歡迎訪問(wèn)我的站點(diǎn),閱讀更多有深度的文章。 實(shí)例變量 和 類變量...

    cuieney 評(píng)論0 收藏0
  • 淺入理解單例模式

    摘要:實(shí)現(xiàn)我們?cè)谶@里引入了一個(gè)私有的構(gòu)造函數(shù),這樣,外部就無(wú)法實(shí)例化這個(gè)對(duì)象了。對(duì)于這個(gè)類,我們無(wú)法生成第二個(gè)對(duì)象,因?yàn)樗臉?gòu)造函數(shù)是私有的,并且方法是私有的,而且,在判斷已經(jīng)有了一個(gè)實(shí)例的情況下默認(rèn)返回該實(shí)例。這就是單例模式。 問(wèn)題 惱人的全局變量 在 PHP 中,甚至不只 PHP 中,我們都會(huì)用到全局變量,以保存全局狀態(tài)??墒?,往往全局變量是全局共享的,任何地方任何代碼都有可能將其覆蓋。...

    CoyPan 評(píng)論0 收藏0
  • (CZ深入淺出Java基礎(chǔ))設(shè)計(jì)模式筆記

    摘要:在設(shè)計(jì)模式中,所有的設(shè)計(jì)模式都遵循這一原則。其實(shí)就是說(shuō)在應(yīng)用程序中,所有的類如果使用或依賴于其他的類,則應(yīng)該依賴這些其他類的抽象類,而不是這些其他類的具體類。使用設(shè)計(jì)模式是為了可重用代碼讓代碼更容易被他人理解保證代碼可靠性。 這是劉意老師的JAVA基礎(chǔ)教程的筆記講的賊好,附上傳送門(mén) 傳智風(fēng)清揚(yáng)-超全面的Java基礎(chǔ) 一、面向?qū)ο笏枷朐O(shè)計(jì)原則 1.單一職責(zé)原則 其實(shí)就是開(kāi)發(fā)人員經(jīng)常說(shuō)的高...

    李昌杰 評(píng)論0 收藏0
  • 設(shè)計(jì)模式單例模式

    摘要:代碼分析構(gòu)造函數(shù)私有化,防止外部直接調(diào)用構(gòu)造函數(shù)通過(guò)改靜態(tài)方法獲取單例對(duì)象這是典型的懶漢式單例方法,低并發(fā)的情況下不會(huì)出現(xiàn)問(wèn)題,若系統(tǒng)壓力增大,并發(fā)量增加將有非常大的可能創(chuàng)建多個(gè)實(shí)例。 前言 終于到周末了,又玩起了最愛(ài)的lol,最近新版本出了一個(gè)特別的天賦--偷錢(qián)(具體名字想不起來(lái)了),配上ez簡(jiǎn)直是吊炸天,我玩的單排,僅用了不到三十分鐘就殺的對(duì)面出不了家,正當(dāng)我看著傷害板沾沾自喜,對(duì)...

    mikasa 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<