国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【設(shè)計(jì)模式】單例模式、“多例模式”的實(shí)現(xiàn)以及對單例的一些思考

這篇具有很好參考價(jià)值的文章主要介紹了【設(shè)計(jì)模式】單例模式、“多例模式”的實(shí)現(xiàn)以及對單例的一些思考。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1.概述

單例模式是設(shè)計(jì)模式中最簡單的一種,對于很多人來說,單例模式也是其接觸的第一種設(shè)計(jì)模式,當(dāng)然,我也不例外。這種設(shè)計(jì)模式在學(xué)習(xí)、面試、工作的過程中廣泛傳播,相信不少人在面試時(shí)遇到過這樣的問題:“說說你最熟悉的集中設(shè)計(jì)模式”,第一個(gè)脫口而出的就是單例模式。

所謂的單例模式,就是在一定的作用范圍內(nèi)保證只有一個(gè)實(shí)例,這種模式,簡單,但是想要使用好它,還需要學(xué)習(xí)一下它延伸出來的其他知識點(diǎn),本篇博文就對單例模式做一下簡單的整理,主要會包含以下幾部分內(nèi)容:

  • 單例模式的代碼如何編寫?
  • 是否需要嚴(yán)格的禁止單例被破壞?
  • 餓漢式和懶漢式應(yīng)該如何選擇?
  • 單例模式存在什么問題?
  • 線程內(nèi)單例和進(jìn)程間單例如何實(shí)現(xiàn)?
  • 什么叫做“多例模式”?

2.單例模式實(shí)現(xiàn)代碼

單例模式的實(shí)現(xiàn)代碼很多,下面會例舉一些常見的方式。

Java中,單例模式的作用范圍一般情況下指的是當(dāng)前的Java進(jìn)程,也就是進(jìn)程內(nèi)的對象保證唯一(當(dāng)然還有線程內(nèi)、進(jìn)程之間的單例,下面會提到),所以我們需要保證實(shí)例只會被初始化一次,如何保證呢?

2.1.餓漢式單例

一個(gè)簡單的做法,就是私有化構(gòu)造方法,也就是不讓外部的客戶端對象來調(diào)用new方法,創(chuàng)建新的實(shí)例,而是在項(xiàng)目啟動(dòng)時(shí),由單例類自行初始化,這就是餓漢式單例

/**
 * 餓漢式單例
 */
public class HungrySingleton {

    private static final HungrySingleton HUNGRY_SINGLETON = new HungrySingleton();

    private HungrySingleton() {}

    public static HungrySingleton getInstance() {
        return HUNGRY_SINGLETON;
    }
}

2.2.懶漢式單例

如果不想再項(xiàng)目啟動(dòng)時(shí)初始化,而是在使用的時(shí)候再初始化對象,可以將對象的創(chuàng)建放到getInstance方法中,這種方式叫做懶漢式單例。這種方式在多線程的情況下會有線程安全問題,需要在創(chuàng)建對象時(shí)加鎖。

/**
 * 懶漢式單例
 */
public class LazySingleton {

    private static volatile LazySingleton lazySingleton;

    private LazySingleton() {}

    public static synchronized LazySingleton getInstance() {
        if (lazySingleton == null) {
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
}

2.3.雙檢鎖單例

在方法加的是類鎖,一次只有一個(gè)線程可以獲取到單例對象,為了提高獲取對象的效率,取消在方法上的類鎖,轉(zhuǎn)而只給創(chuàng)建對象的那一行代碼加鎖。但是在并發(fā)的情況下,多個(gè)線程同時(shí)進(jìn)入getInstance方法,都可以通過lazySingleton == null的判斷,并在加鎖那一行排隊(duì),每個(gè)線程都會創(chuàng)建一個(gè)新的對象,所以,我們需要在鎖里面再判斷一次對象是否創(chuàng)建。
這種在加鎖的代碼前后都進(jìn)行一次相同判斷的做法,我們叫做雙重檢查鎖,簡稱:雙檢鎖。

/**
 * 雙檢鎖單例
 */
public class LazySingleton {

    private static volatile LazySingleton lazySingleton;

    private LazySingleton() {}

    public static LazySingleton getInstance() {
        if (lazySingleton == null) {
            synchronized (LazySingleton.class) {
                if (lazySingleton == null) {
                    lazySingleton = new LazySingleton();
                }
            }
        }
        return lazySingleton;
    }
}

2.4.靜態(tài)內(nèi)部類單例

上面的懶漢式是為了保證懶加載的同時(shí),又不能有線程安全問題,我們采用了加鎖的方式,那么不加鎖行不行呢?
當(dāng)然是可以的,我們采用靜態(tài)內(nèi)部類在受訪問時(shí)才會初始化的特性,來實(shí)現(xiàn)懶加載。

/**
 * 靜態(tài)內(nèi)部類單例
 */
public class StaticClassSingleton {

    private StaticClassSingleton() {
    }

    public static StaticClassSingleton getInstance() {
        return InnerStaticClassSingleton.STATIC_CLASS_SINGLETON;
    }

    private static class InnerStaticClassSingleton {
        private static final StaticClassSingleton STATIC_CLASS_SINGLETON = new StaticClassSingleton();
    }
}

2.5.枚舉單例

Java中的枚舉是天然的單例模式,這種方式實(shí)現(xiàn)最簡單,而且不會有線程安全問題,也能避免通過反射或者反序列化創(chuàng)建新的對象。
下面代碼中的INSTANCE就是單例對象了。

/**
 * 枚舉單例
 */
public enum EnumSingleton {
    INSTANCE;
}

3.對單例的一些思考

3.1.是否需要嚴(yán)格的禁止單例被破壞?

在上面的代碼例子中,我們采用的方式是私有化構(gòu)造方法方法來避免外部對象new出新的單例對象,但這種方式并不能完全避免創(chuàng)建出新的對象。其實(shí)上面的枚舉單例中已經(jīng)提到了,可以通過反射、反序列化等方式,創(chuàng)建出新的對象。

在考慮如何避免通過反射、反序列化創(chuàng)建對象,可以先思考一下,有沒有必要去避免?

還是回到最初那個(gè)點(diǎn),我們用了這么多方式來實(shí)現(xiàn)單例模式,最終的目的就是為了在進(jìn)程內(nèi)的作用范圍內(nèi)只有一個(gè)實(shí)例。而在代碼的開發(fā)過程中,我們做好規(guī)范和約束,以人為的方式來控制對象的創(chuàng)建數(shù)量,哪怕沒有私有化構(gòu)造方法方法也能保證單例。而我們私有化構(gòu)造方法,更多的是給開發(fā)者做出一個(gè)提示,這個(gè)類是個(gè)單例類,并且防止一定的誤操作。
可以想象一下,我們要完全將各類創(chuàng)建和初始化的邏輯都“封閉”掉,代碼會臃腫到什么地步,而這部分“封閉”的邏輯在業(yè)務(wù)開發(fā)中我們完全使用不到,所以更建議以一種“約定由于配置”的方式來處理單例的創(chuàng)建問題。

綜上,做到私有化構(gòu)造方法這一步就夠了,不需要過度開發(fā)。

3.2.懶漢式真的比餓漢式更佳嗎?

懶漢式主要是為了做懶加載,當(dāng)單例對象沒有使用的時(shí)候就不創(chuàng)建和初始化,特別是初始化是需要加載的資源比較多、比較耗時(shí)的時(shí)候,用懶加載可以加快項(xiàng)目啟動(dòng)的速度,同時(shí)又能減少系統(tǒng)的資源浪費(fèi)。
但是從另一個(gè)角度講,如果不是在啟動(dòng)的時(shí)候初始化,那就是在客戶端調(diào)用的時(shí)候初始化,想象一下一個(gè)高并發(fā)的互聯(lián)網(wǎng)項(xiàng)目,如果在客戶端調(diào)用的時(shí)候再做耗時(shí)的初始化動(dòng)作,就可能造成接口的請求時(shí)間過長,接口超時(shí)等,會影響一批用戶的使用體驗(yàn)。
另外,如果初始化的過程中存在一些異常情況,我們應(yīng)該讓問題在項(xiàng)目啟動(dòng)時(shí)就暴露出來,及時(shí)修復(fù),而不是在用戶使用的時(shí)候才暴露問題。

綜上,在業(yè)務(wù)開發(fā)中或許餓漢式單例是更好的選擇。

3.3.單例存在的問題

單例模式編寫和使用都很簡單,但是它也存在一些問題,例如:

  • 面向?qū)ο笾С植缓?/strong>:單例模式在作用范圍內(nèi)只有一個(gè)實(shí)例,那就無法通過創(chuàng)建更多的實(shí)例來使用面向?qū)ο蟮某橄?、繼承、多態(tài)等特性,更像是一種面向過程的寫法。
  • 違反開閉原則:無法拓展,每一次迭代都需要修改原有的代碼。
  • 違反單一職責(zé):單例模式既創(chuàng)建對象、又管理對象,職責(zé)模糊,可能會導(dǎo)致代碼變得復(fù)雜。

綜上,單例模式存在一定的問題,如果存在拓展的需求就盡可能的避免使用單例模式。

但如果在不需要大量的拓展,又沒有業(yè)務(wù)間的復(fù)雜依賴關(guān)系,使用單例模式就比較簡潔方便也不失為一種選擇,例如各種無狀態(tài)的工具類。

4.其他作用范圍的單例模式

4.1.線程內(nèi)的單例

即單例對象在線程內(nèi)時(shí)唯一的,線程之間不是唯一的,我們開發(fā)中有一種很常見的情況:線程局部變量,一般是通過ThreadLocal來做的。
實(shí)現(xiàn)原理也比較簡單,其實(shí)就是使用一個(gè)全局的Map來保存對象,以線程對象threadkey,以需要保存的單例對象為value,這樣就保證了一個(gè)線程只對應(yīng)一個(gè)對象。
在業(yè)務(wù)流程中的用戶登錄信息,往往就是保存在ThreadLocal中的,另外PageHelper這個(gè)著名的工具類也是通過ThreadLocal來實(shí)現(xiàn)的。


如果想了解ThreadLocal的使用方式,可以參考我的另一篇博客《【并發(fā)編程】(九)線程安全的代碼及ThreadLocal的使用》
如果想了解它詳細(xì)的實(shí)現(xiàn)原理,可以參考《【并發(fā)編程】(十)線程局部變量——ThreadLocal原理詳解》

4.2.進(jìn)程間的單例

進(jìn)程間的單例,更常用的一種說法分布式環(huán)境中的單例,這類需求我們使用的也比較多,其實(shí)現(xiàn)原理也比較簡單,就是將單例對象通過序列化的方式存儲在一個(gè)多個(gè)服務(wù)都會共同訪問的存儲區(qū)域中,例如一個(gè)共享的文件中、一些分布式的中間件中,例如rediszk等等,而最常見的當(dāng)然就是分布式鎖
我們只需要為單例對象創(chuàng)建出一個(gè)唯一標(biāo)識,在每個(gè)服務(wù)中判斷唯一標(biāo)識是否存在即可。

5.“多例模式”

多例模式是單例模式中的一種特例,即可以在一定數(shù)量范圍內(nèi)創(chuàng)建類的多個(gè)實(shí)例,還有一層理解就是不同類型的對象可以創(chuàng)建多個(gè),想通類型的對象只能創(chuàng)建一個(gè),后者的概念使用的更多。

以日志打印為例,我們引入Slf4J后通過下面的方式獲得一個(gè)日志對象:

private Logger logger = LoggerFactory.getLogger(xxx.class);

這里獲取的logger如果后面的class對象相同,獲取的就是同一個(gè)對象,這種方式更像是工廠模式,在代碼中看到的也是工廠模式,如下圖:【設(shè)計(jì)模式】單例模式、“多例模式”的實(shí)現(xiàn)以及對單例的一些思考,# 設(shè)計(jì)模式,架構(gòu)與設(shè)計(jì),單例模式,設(shè)計(jì)模式
我們進(jìn)入這個(gè)工廠模式的方法后,可以看到下面的代碼:
【設(shè)計(jì)模式】單例模式、“多例模式”的實(shí)現(xiàn)以及對單例的一些思考,# 設(shè)計(jì)模式,架構(gòu)與設(shè)計(jì),單例模式,設(shè)計(jì)模式
這里就非常明顯了,這就是一種單例模式的創(chuàng)建方式,通過一個(gè)Map將單例對象管理起來,如果Map中有就直接返回,如果沒有就創(chuàng)建一個(gè)并放入到Map中,這里的對象都是logger對象,只是使用日志的類不一樣,這就是多例模式的一種體現(xiàn)。

另外,在Spring中如果配置的bean是單例的,其創(chuàng)建方式也與這種方式類似。

6.總結(jié)

本來主要講述了以下幾個(gè)點(diǎn):文章來源地址http://www.zghlxwxcb.cn/news/detail-723380.html

  • 單例模式的編寫方式
    餓漢式、懶漢式、靜態(tài)內(nèi)部類、枚舉
  • 是否需要嚴(yán)格的禁止單例被破壞:
    沒有必要寫的太嚴(yán)格,可以通過規(guī)范的方式來約束
  • 餓漢式和懶漢式應(yīng)該如何選擇:
    讓耗時(shí)操作提前初始化,讓問題提早暴露,及時(shí)修改,而不是讓用戶去發(fā)現(xiàn)
  • 單例模式存在什么問題
    沒有面向?qū)ο螅卣剐圆?/li>
  • 線程內(nèi)單例和進(jìn)程間單例如何實(shí)現(xiàn)
    線程內(nèi)單例通過線程局部變量來實(shí)現(xiàn),進(jìn)程間的單例通過共享的存儲區(qū)域來實(shí)現(xiàn)
  • 什么叫做“多例模式”
    在一定數(shù)量范圍內(nèi)可以創(chuàng)建多個(gè),或者不同的類可以有多個(gè)、相同的類只能有一個(gè)

到了這里,關(guān)于【設(shè)計(jì)模式】單例模式、“多例模式”的實(shí)現(xiàn)以及對單例的一些思考的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Python入門【?編輯、組合、設(shè)計(jì)模式_工廠模式實(shí)現(xiàn) 、設(shè)計(jì)模式_單例模式實(shí)現(xiàn)、工廠和單例模式結(jié)合、異常是什么?異常的解決思路 】(十七)

    Python入門【?編輯、組合、設(shè)計(jì)模式_工廠模式實(shí)現(xiàn) 、設(shè)計(jì)模式_單例模式實(shí)現(xiàn)、工廠和單例模式結(jié)合、異常是什么?異常的解決思路 】(十七)

    ??作者簡介:大家好,我是愛敲代碼的小王,CSDN博客博主,Python小白 ??系列專欄:python入門到實(shí)戰(zhàn)、Python爬蟲開發(fā)、Python辦公自動(dòng)化、Python數(shù)據(jù)分析、Python前后端開發(fā) ??如果文章知識點(diǎn)有錯(cuò)誤的地方,請指正!和大家一起學(xué)習(xí),一起進(jìn)步?? ??如果感覺博主的文章還不錯(cuò)的

    2024年02月14日
    瀏覽(20)
  • 【設(shè)計(jì)模式學(xué)習(xí)1】什么是單例模式?單例模式的幾種實(shí)現(xiàn)。

    【設(shè)計(jì)模式學(xué)習(xí)1】什么是單例模式?單例模式的幾種實(shí)現(xiàn)。

    單例模式是在內(nèi)存中只創(chuàng)建一個(gè)對象的模式,它保證一個(gè)類只有一個(gè)實(shí)例。 如上圖所示,多線程情況下,在時(shí)刻T,線程A和線程B都判斷single為null,從而進(jìn)入if代碼塊中都執(zhí)行了new Single()的操作創(chuàng)建了兩個(gè)對象,就和我們當(dāng)初的單例初衷相悖而行。 1、第一次判空目的:為了縮

    2024年02月15日
    瀏覽(21)
  • 設(shè)計(jì)模式——C++11實(shí)現(xiàn)單例模式(餓漢模式、懶漢模式),與單例的進(jìn)程

    本文將介紹單例模式,使用C++11實(shí)現(xiàn)多個(gè)版本的單例模式,分析各自的優(yōu)缺點(diǎn)。最后提及如何實(shí)現(xiàn)一個(gè)單例的進(jìn)程。 單例模式屬于創(chuàng)建型模式,提供了一種創(chuàng)建對象的方式。 單例模式確保一個(gè)類只有一個(gè)實(shí)例。通過一個(gè)類統(tǒng)一地訪問這個(gè)實(shí)例。 思想:將構(gòu)造函數(shù)設(shè)置為私有

    2024年02月09日
    瀏覽(22)
  • 設(shè)計(jì)模式學(xué)習(xí)(一)單例模式的幾種實(shí)現(xiàn)方式

    設(shè)計(jì)模式學(xué)習(xí)(一)單例模式的幾種實(shí)現(xiàn)方式

    目錄 前言 餓漢式 懶漢式 懶漢式DCLP 局部靜態(tài)式(Meyers\\\' Singleton) 單例模板 參考文章 單例模式,其核心目標(biāo)是確保在程序運(yùn)行的過程中,有且只有存在一個(gè)實(shí)例才能保證他們的邏輯正確性以及良好的效率。因此單例模式的實(shí)現(xiàn)思路就是確保一個(gè)類有且只有一個(gè)實(shí)例,并提供

    2024年03月19日
    瀏覽(52)
  • 【設(shè)計(jì)模式】23種設(shè)計(jì)模式——單例模式(原理講解+應(yīng)用場景介紹+案例介紹+Java代碼實(shí)現(xiàn))

    【設(shè)計(jì)模式】23種設(shè)計(jì)模式——單例模式(原理講解+應(yīng)用場景介紹+案例介紹+Java代碼實(shí)現(xiàn))

    介紹 所謂類的單例設(shè)計(jì)模式,就是采取一定的方法, 保證在整個(gè)的軟件系統(tǒng)中,對某個(gè)類只能存在一個(gè)對象實(shí)例 ,并且該類只提供一個(gè)取得其對象實(shí)例的方法(靜態(tài)方法)。 比如Hibernate的SessionFactory,它充當(dāng)數(shù)據(jù)存儲源的代理,并負(fù)責(zé)創(chuàng)建Session對象。SessionFactory并不是輕量

    2024年02月13日
    瀏覽(32)
  • 用Rust實(shí)現(xiàn)23種設(shè)計(jì)模式之單例

    話不多說,上代碼! 在這個(gè)例子中,我們使用了 Arc (原子引用計(jì)數(shù))和 Mutex (互斥鎖)來實(shí)現(xiàn)線程安全的單例。通過 get_instance 方法,我們可以獲取到單例實(shí)例,并對實(shí)例進(jìn)行操作。 使用 lazy_static crate: lazy_static crate 是一個(gè)常用的 Rust crate,可以實(shí)現(xiàn)懶加載的全局靜態(tài)變量

    2024年02月14日
    瀏覽(27)
  • 【Linux】簡單線程池的設(shè)計(jì)與實(shí)現(xiàn) -- 單例模式

    【Linux】簡單線程池的設(shè)計(jì)與實(shí)現(xiàn) -- 單例模式

    線程池: 一種線程使用模式。線程過多會帶來調(diào)度開銷,進(jìn)而影響緩存局部性和整體性能。而 線程池維護(hù)著多個(gè)線程,等待著監(jiān)督管理者分配可并發(fā)執(zhí)行的任務(wù) 。這避免了在處理短時(shí)間任務(wù)時(shí)創(chuàng)建與銷毀線程的代價(jià)。線程池不僅能夠保證內(nèi)核的充分利用,還能防止過分調(diào)度。

    2024年02月12日
    瀏覽(21)
  • [設(shè)計(jì)模式Java實(shí)現(xiàn)附plantuml源碼~創(chuàng)建型] 確保對象的唯一性~單例模式

    [設(shè)計(jì)模式Java實(shí)現(xiàn)附plantuml源碼~創(chuàng)建型] 確保對象的唯一性~單例模式

    前言: 為什么之前寫過Golang 版的設(shè)計(jì)模式,還在重新寫 Java 版? 答:因?yàn)閷τ谖叶?,?dāng)然也希望對正在學(xué)習(xí)的大伙有幫助。Java作為一門純面向?qū)ο蟮恼Z言,更適合用于學(xué)習(xí)設(shè)計(jì)模式。 為什么類圖要附上uml 因?yàn)楹芏嗳藢W(xué)習(xí)有做筆記的習(xí)慣,如果單純的只是放一張圖片,那

    2024年01月19日
    瀏覽(22)
  • 單例設(shè)計(jì)模式精講(餓漢式和懶漢式實(shí)現(xiàn)的重要方法)

    目錄 什么叫做單例模式? 餓漢式和懶漢式的區(qū)別? 餓漢式-方式1(靜態(tài)變量方式) 餓漢式-方式2(靜態(tài)代碼塊方式) 懶漢式-方式1(線程不安全) 懶漢式-方式2(線程安全) 懶漢式-方式3(雙重檢查鎖) 懶漢式-方式4(靜態(tài)內(nèi)部類方式) 什么叫做單例模式? ????????涉

    2024年02月12日
    瀏覽(16)
  • C++中特殊類的設(shè)計(jì)與單例模式的簡易實(shí)現(xiàn)

    C++中特殊類的設(shè)計(jì)與單例模式的簡易實(shí)現(xiàn)

    對于這種特殊類的設(shè)計(jì)我們一般都是優(yōu)先考慮私有構(gòu)造函數(shù)。 然后對于一些特殊要求就直接通過靜態(tài)成員函數(shù)的實(shí)現(xiàn)來完成。 ?這里選擇禁掉拷貝構(gòu)造函數(shù)和拷貝函數(shù)是為了防止將已創(chuàng)建的對象去拷貝構(gòu)造新的對象。 ?這里如果沒有禁掉operator new和operator delete的話就會導(dǎo)致以

    2024年01月18日
    瀏覽(28)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包