亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

深入理解單例模式

FuisonDesign / 1259人閱讀

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

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

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

本文主要內(nèi)容

1 單例模式簡介 1.1 定義

保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。

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

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

簡單來說使用單例模式可以帶來下面幾個好處:

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

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

1.3 為什么不使用全局變量確保一個類只有一個實例呢?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

public class Singleton {

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

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

我們上面使用到了volatile關(guān)鍵字來保證數(shù)據(jù)的可見性,關(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對于volatile關(guān)鍵字的實現(xiàn)會導(dǎo)致雙重檢查加鎖的失效。
2.4 其他方式(枚舉)

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

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

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

使用方法:

public class ESTest {

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

    }

}

《Effective Java 中文版 第二版》

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

《Java與模式》

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

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

餓漢方式(線程安全)

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

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

枚舉方式

參考:

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

《Effective Java 中文版 第二版》

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

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

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

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/69511.html

相關(guān)文章

  • 深入java單例模式

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

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

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

    cuieney 評論0 收藏0
  • 淺入理解單例模式

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

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

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

    李昌杰 評論0 收藏0
  • 設(shè)計模式單例模式

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

    mikasa 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<