最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文搞懂設(shè)計(jì)模式中的單例模式

 更新時(shí)間:2023年08月04日 10:36:16   作者:wh柒八九  
這篇文章主要介紹了一文搞懂設(shè)計(jì)模式中的單例模式,單例模式是最簡(jiǎn)單的設(shè)計(jì)模式之一,屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的方式,確保只有單個(gè)對(duì)象被創(chuàng)建,需要的朋友可以參考下

單例模式

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

單例模式的意義

通常面試官會(huì)很籠統(tǒng)的問你,什么是單例模式?單例模式用來解決了什么痛點(diǎn)?沒有單例模式我們會(huì)怎么辦?單例模式他有什么缺點(diǎn)嗎?

單例模式是最簡(jiǎn)單的設(shè)計(jì)模式之一,屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的方式,確保只有單個(gè)對(duì)象被創(chuàng)建。

這個(gè)設(shè)計(jì)模式主要目的是想在整個(gè)系統(tǒng)中只能出現(xiàn)類的一個(gè)實(shí)例,即一個(gè)類只有一個(gè)對(duì)象。

單例模式的解決的痛點(diǎn)就是節(jié)約資源,節(jié)省時(shí)間從兩個(gè)方面看:

  • 由于頻繁使用的對(duì)象,可以省略創(chuàng)建對(duì)象所花費(fèi)的時(shí)間,這對(duì)于那些重量級(jí)的對(duì)象而言,是很重要的.
  • 因?yàn)椴恍枰l繁創(chuàng)建對(duì)象,我們的GC壓力也減輕了,而在GC中會(huì)有STW(stop the world),從這一方面也節(jié)約了GC的時(shí)間

單例模式的缺點(diǎn):

簡(jiǎn)單的單例模式設(shè)計(jì)開發(fā)都比較簡(jiǎn)單,但是復(fù)雜的單例模式需要考慮線程安全等并發(fā)問題,引入了部分復(fù)雜度。

擴(kuò)展:從你的回答中能進(jìn)行哪些擴(kuò)展呢?我們談到了GC,有可能這時(shí)候就會(huì)問你GC,STW等知識(shí)。談缺點(diǎn)的時(shí)候談到了復(fù)雜的單例模式,

這個(gè)時(shí)候可能會(huì)問你讓你設(shè)計(jì)一個(gè)優(yōu)秀的單例模式你會(huì)怎么設(shè)計(jì),會(huì)怎么實(shí)現(xiàn)?

單例模式的設(shè)計(jì)

通常這里面試官會(huì)問你單例模式怎么設(shè)計(jì),需要看重哪些方面?一般來說單例模式有哪些實(shí)現(xiàn)方式?

通常單例模式在Java語言中,有兩種構(gòu)建方式

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

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

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

設(shè)計(jì)單例模式的時(shí)候一般需要考慮幾種因素:-線程安全 -延遲加載 -代碼安全:如防止序列化攻擊,防止反射攻擊(防止反射進(jìn)行私有方法調(diào)用) -性能因素

一般來說,我們?nèi)ゾW(wǎng)上百度去搜大概有7,8種實(shí)現(xiàn),下面列舉一下需要重點(diǎn)知道的餓漢,懶漢(線程安全,線程非安全),雙重檢查(DCL)(重點(diǎn)),內(nèi)部類,以及枚舉(重點(diǎn)),

下面比對(duì)下各個(gè)實(shí)現(xiàn):

名稱線程安全并發(fā)性能好可以延遲加載序列化/反序列化安全能抵御反射攻擊
餓漢式YYNNN
懶漢式(不加鎖)NYYNN
懶漢式(加鎖)YNYNN
DCLYYYNN
靜態(tài)內(nèi)部類YYYNN
枚舉YYNYY

擴(kuò)展:

我們上面說到了各個(gè)模式的實(shí)現(xiàn),這個(gè)時(shí)候很有可能會(huì)叫你手寫各個(gè)模式的代碼。當(dāng)然也有可能會(huì)問你線程安全,代碼安全等知識(shí)。

餓漢模式

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return instance;
    }
}

所謂 “餓漢方式” 就是說JVM在加載這個(gè)類時(shí)就馬上創(chuàng)建此唯一的單例實(shí)例,不管你用不用,先創(chuàng)建了再說

如果一直沒有被使用,便浪費(fèi)了空間,典型的空間換時(shí)間,每次調(diào)用的時(shí)候,就不需要再判斷,節(jié)省了運(yùn)行時(shí)間。

餓漢模式代碼比較簡(jiǎn)單,對(duì)象在類中被定義為private static,通過getInstance(),通過java的classLoader機(jī)制保證了單例對(duì)象唯一。

擴(kuò)展:

有可能會(huì)問instance什么時(shí)候被初始化?  

Singleton類被加載的時(shí)候就會(huì)被初始化,java虛擬機(jī)規(guī)范雖然沒有強(qiáng)制性約束在什么時(shí)候開始類加載過程,但是對(duì)于類的初始化,虛擬機(jī)規(guī)范則嚴(yán)格規(guī)定了有且只有四種情況必須立即對(duì)類進(jìn)行初始化,遇到new、getStatic、putStatic或invokeStatic這4條字節(jié)碼指令時(shí),如果類沒有進(jìn)行過初始化,則需要先觸發(fā)其初始化。

生成這4條指令最常見的java代碼場(chǎng)景是:

1)使用new關(guān)鍵字實(shí)例化對(duì)象

2)讀取一個(gè)類的靜態(tài)字段(被final修飾、已在編譯期把結(jié)果放在常量池的靜態(tài)字段除外)

3)設(shè)置一個(gè)類的靜態(tài)字段(被final修飾、已在編譯期把結(jié)果放在常量池的靜態(tài)字段除外)

4)調(diào)用一個(gè)類的靜態(tài)方法  

class的生命周期?  

class的生命周期一般來說會(huì)經(jīng)歷加載、連接、初始化、使用、和卸載五個(gè)階段  

class的加載機(jī)制  

這里可以聊下classloader的雙親委派模型。

懶漢式(非線程安全和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;  
      }  
 }

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

但是上面這種方式很明顯是線程不安全的,如果多個(gè)線程同時(shí)訪問getInstance()方法時(shí)就會(huì)出現(xià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)行了主要包括:

為了減少獲得鎖和釋放鎖帶來的性能消耗而引入的偏向鎖和輕量級(jí)鎖以及其它各種優(yōu)化之后執(zhí)行效率有了顯著提升。

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

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

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

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同步塊里面能夠保證只創(chuàng)建一個(gè)對(duì)象。但是通過在synchronized的外面增加一層判斷,就可以在對(duì)象一經(jīng)創(chuàng)建以后,不再進(jìn)入synchronized同步塊。這種方案不僅減小了鎖的粒度,保證了線程安全,性能方面也得到了大幅提升。

同時(shí)這里要注意一定要說volatile,這個(gè)很關(guān)鍵,volatile一般用于多線程的可見性,但是這里是用來防止指令重排序的。

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

懶漢式(登記式/靜態(tài)內(nèi)部類方式)

靜態(tài)內(nèi)部實(shí)現(xiàn)的單例是懶加載的且線程安全。

只有通過顯式調(diào)用 getInstance 方法時(shí),才會(huì)顯式裝載 SingletonHolder 類,從而實(shí)例化 instance(只有第一次使用這個(gè)單例的實(shí)例的時(shí)候才加載,同時(shí)不會(huì)有線程安全問題)。

public class Singleton {  
    private static class SingletonHolder {  
    private static final Singleton INSTANCE = new Singleton();  
    }  
    private Singleton (){}  
    public static final Singleton getInstance() {  
    return SingletonHolder.INSTANCE;  
    }  
}  

餓漢式(枚舉方式)

這種實(shí)現(xiàn)方式還沒有被廣泛采用,但這是實(shí)現(xiàn)單例模式的最佳方法。 它更簡(jiǎn)潔,自動(dòng)支持序列化機(jī)制,絕對(duì)防止多次實(shí)例化 (如果單例類實(shí)現(xiàn)了Serializable接口,默認(rèn)情況下每次反序列化總會(huì)創(chuàng)建一個(gè)新的實(shí)例對(duì)象,同時(shí)這種方式也是《Effective Java 》以及《Java與模式》的作者推薦的方式。

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)單例
	}
}

擴(kuò)展閱讀:

《Effective Java 中文版 第二版》

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

《Java與模式》

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

本文小結(jié)

單例模式雖然看起來簡(jiǎn)單,但是設(shè)計(jì)的Java基礎(chǔ)知識(shí)非常多,如static修飾符、synchronized修飾符、volatile修飾符、enum等。

這里的每一個(gè)知識(shí)點(diǎn)都可以變成面試官下手的考點(diǎn),而單例只是作為一個(gè)引子,考到最后看你到底掌握了多少??茨愕膹V度和深度到底是怎么樣的。

到此這篇關(guān)于一文搞懂設(shè)計(jì)模式中的單例模式的文章就介紹到這了,更多相關(guān)設(shè)計(jì)模式中的單例模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java對(duì)接第三方接口的3種常用方式

    java對(duì)接第三方接口的3種常用方式

    java語言中調(diào)用第三方接口,可以使用的方法有很多,下面這篇文章主要給大家介紹了關(guān)于java對(duì)接第三方接口的3種常用方式,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-04-04
  • java根據(jù)模板導(dǎo)出PDF的詳細(xì)實(shí)現(xiàn)過程

    java根據(jù)模板導(dǎo)出PDF的詳細(xì)實(shí)現(xiàn)過程

    前段時(shí)間因?yàn)橄嚓P(guān)業(yè)務(wù)需求需要后臺(tái)生成pdf文件,所以下面這篇文章主要給大家介紹了關(guān)于java根據(jù)模板導(dǎo)出PDF的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-02-02
  • Java向上向下轉(zhuǎn)型詳解

    Java向上向下轉(zhuǎn)型詳解

    這篇文章主要為大家詳細(xì)介紹了Java向上向下轉(zhuǎn)型,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-09-09
  • Spring中基于XML的面向切面編程(AOP)詳解

    Spring中基于XML的面向切面編程(AOP)詳解

    這篇文章主要詳細(xì)介紹了Spring中基于XML的面向切面編程(AOP),文中通過代碼示例給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-04-04
  • Java實(shí)踐練習(xí)輕松幾行實(shí)現(xiàn)追書神器

    Java實(shí)踐練習(xí)輕松幾行實(shí)現(xiàn)追書神器

    讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用Java實(shí)現(xiàn)一個(gè)追書神器,用技術(shù)改變生活,大家可以在過程中查缺補(bǔ)漏,提升水平
    2021-10-10
  • springboot3整合knife4j詳細(xì)圖文教程(swagger增強(qiáng))

    springboot3整合knife4j詳細(xì)圖文教程(swagger增強(qiáng))

    開發(fā)api提供對(duì)應(yīng)的接口規(guī)范進(jìn)行聯(lián)調(diào)或并行開發(fā),api文檔管理必不可少,常用的Knife4j基于swagger(依賴已經(jīng)compile),可以進(jìn)行管理,下面這篇文章主要給大家介紹了關(guān)于springboot3整合knife4j的相關(guān)資料,需要的朋友可以參考下
    2024-03-03
  • spring 整合JDBC和AOP事務(wù)的方法

    spring 整合JDBC和AOP事務(wù)的方法

    這篇文章主要介紹了spring 整合JDBC和AOP事務(wù)的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-07-07
  • SpringBoot項(xiàng)目長時(shí)間未訪問導(dǎo)致Tomcat臨時(shí)文件夾被刪除的解決方案

    SpringBoot項(xiàng)目長時(shí)間未訪問導(dǎo)致Tomcat臨時(shí)文件夾被刪除的解決方案

    做SpringBoot開發(fā)的同學(xué),大概率會(huì)遇到一個(gè)隱蔽的坑:項(xiàng)目部署在Linux服務(wù)器上,但如果系統(tǒng)長時(shí)間(比如10天)無人訪問,再次上傳文件就會(huì)報(bào)錯(cuò),排查半天找不到原因,其實(shí)這個(gè)問題的根源,和Tomcat的臨時(shí)文件夾密切相關(guān),今天就帶大家徹底搞懂這個(gè)問題,從原因到解決方案
    2026-02-02
  • AQS同步組件CyclicBarrier循環(huán)屏障用例剖析

    AQS同步組件CyclicBarrier循環(huán)屏障用例剖析

    這篇文章主要為大家介紹了AQS同步組件CyclicBarrier循環(huán)屏障用例剖析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • JavaScript中的isTrusted屬性及其應(yīng)用場(chǎng)景詳解

    JavaScript中的isTrusted屬性及其應(yīng)用場(chǎng)景詳解

    在現(xiàn)代 Web 開發(fā)中,JavaScript 是構(gòu)建交互式應(yīng)用的核心語言,隨著前端技術(shù)的不斷發(fā)展,開發(fā)者需要處理越來越多的復(fù)雜場(chǎng)景,例如事件處理、數(shù)據(jù)傳遞和狀態(tài)管理等,本文將通過一個(gè)實(shí)際案例,深入探討 isTrusted 屬性的來源、作用,需要的朋友可以參考下
    2025-01-01

最新評(píng)論

东城区| 宁夏| 紫金县| 美姑县| 兴隆县| 紫阳县| 乐陵市| 玛纳斯县| 肃宁县| 长兴县| 梁山县| 施甸县| 邢台县| 昌都县| 永清县| 阿拉善右旗| 彭阳县| 惠东县| 彰武县| 甘泉县| 隆回县| 通渭县| 永顺县| 阿鲁科尔沁旗| 桓台县| 万荣县| 宁阳县| 榆林市| 勃利县| 滦平县| 南平市| 许昌县| 芦山县| 花莲市| 台东市| 伊吾县| 霍城县| 永济市| 寻乌县| 烟台市| 闽清县|