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

資訊專欄INFORMATION COLUMN

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

luxixing / 1869人閱讀

摘要:雙重檢查鎖單例模式懶漢單例模式中,我們并不需要整個(gè)方法都是同步的,我們只需要確保再創(chuàng)建的時(shí)候,進(jìn)行同步即可。單例模式的缺點(diǎn)優(yōu)點(diǎn)在開(kāi)頭已經(jīng)說(shuō)明了,單例模式的缺點(diǎn)在于它一般沒(méi)有接口,擴(kuò)展困難,基本上修改源代碼是擴(kuò)展單例模式的唯一方法。

單例模式 定義:

確保某一個(gè)類只有一個(gè)實(shí)例對(duì)象,并且該對(duì)象是自行實(shí)例化的,通過(guò)統(tǒng)一的接口向整個(gè)系統(tǒng)提供這個(gè)實(shí)例對(duì)象。

使用場(chǎng)景:

避免產(chǎn)生多個(gè)對(duì)象消耗過(guò)多的資源(比如該對(duì)象需要用到IO,Database等等),或者某個(gè)類的實(shí)例化對(duì)象應(yīng)該只有一個(gè)的情況。

因?yàn)閮?nèi)存中只有一個(gè)實(shí)例對(duì)象的存在,減少了內(nèi)存開(kāi)支,同時(shí),如果該對(duì)象的產(chǎn)生需要較多資源的時(shí)候(內(nèi)部需要依賴其他對(duì)象...),我們可以采取只生成一個(gè)對(duì)象,然后讓這個(gè)對(duì)象永久駐留在內(nèi)存中的方式實(shí)現(xiàn)。

如果需要定義大量的靜態(tài)常量和靜態(tài)方法,也可以采用單例模式實(shí)現(xiàn)。

關(guān)鍵點(diǎn):

1.構(gòu)造函數(shù)不對(duì)外開(kāi)放,一般為private。

2.通過(guò)一個(gè)static方法或者枚舉返回給外部單例對(duì)象。

3.在多線程的條件下也能保證只有一個(gè)單例對(duì)象。

4.確保單例類對(duì)象再反序列化的時(shí)候不會(huì)創(chuàng)建新的對(duì)象。

實(shí)現(xiàn)方式: 1.餓漢單例模式
public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton(){}

    public static Singleton getInstance(){
        return instance;
    }
}

優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單,在類加載的時(shí)候完成了初始化工作,避免了多線程同步問(wèn)題。

缺點(diǎn):沒(méi)有實(shí)現(xiàn)懶加載,如果這個(gè)單例對(duì)象沒(méi)有被使用過(guò),但是對(duì)應(yīng)的類卻加載到內(nèi)存中的話,也會(huì)白白的占用不必要的內(nèi)存。

2.懶漢單例模式
public class Singleton{
    private static Singleton instance = null;
    
    private Singleton(){}
    
    public static synchronized Singleton getInstance(){
        if(instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}

優(yōu)點(diǎn):實(shí)現(xiàn)了懶加載,在用到單例對(duì)象的時(shí)候再對(duì)其進(jìn)行初始化,一定程度上節(jié)約了資源。

缺點(diǎn):getInstance掛了一把鎖,每次獲取這個(gè)單例對(duì)象都需要同步,不管是不是并發(fā)情況下,都會(huì)早成不必要的同步開(kāi)銷。

3.DCL雙重檢查鎖單例模式

懶漢單例模式中,我們并不需要整個(gè)getInstance方法都是同步的,我們只需要確保再instance創(chuàng)建的時(shí)候,進(jìn)行同步即可。

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

優(yōu)點(diǎn):線程安全,懶加載,執(zhí)行效率高,只有在instance為null的時(shí)候才會(huì)有同步開(kāi)銷。

缺點(diǎn):

Double-Checked Lock看起來(lái)是非常完美的。但是根據(jù)Java的語(yǔ)言規(guī)范,上面的代碼并非絕對(duì)可靠。
出現(xiàn)上述問(wèn)題, 最重要的2個(gè)原因如下:

1, 編譯器優(yōu)化了程序指令, 以加快cpu處理速度.
2, 多核cpu動(dòng)態(tài)調(diào)整指令順序,允許指令亂序執(zhí)行, 以加快并行運(yùn)算能力.

問(wèn)題出現(xiàn)的順序:

1, 線程A, 發(fā)現(xiàn)對(duì)象未實(shí)例化, 準(zhǔn)備開(kāi)始實(shí)例化

2, 由于編譯器優(yōu)化了程序指令, 允許對(duì)象在構(gòu)造函數(shù)未調(diào)用完前, 將共享變量的引用指向部分構(gòu)造的對(duì)象, 雖然對(duì)象未完全實(shí)例化, 但已經(jīng)不為null了.

3, 線程B, 發(fā)現(xiàn)部分構(gòu)造的對(duì)象已不是null, 則直接返回了該對(duì)象(此時(shí)它為null本應(yīng)該先創(chuàng)建再返回卻直接返回了)。

通俗來(lái)說(shuō),如果線程A的指令發(fā)現(xiàn)instance為null,則會(huì)去執(zhí)行初始化的指令,初始化指令最終翻譯成匯編指令可能是如下三個(gè)部分:

①為內(nèi)存對(duì)象分配內(nèi)存

②構(gòu)造函數(shù)初始化成員字段

③將創(chuàng)建的對(duì)象指定到分配的內(nèi)存空間中

如果123順序執(zhí)行是沒(méi)有問(wèn)題的,但是可能存在132亂序執(zhí)行的情況,如果3執(zhí)行完成,CPU切換到了另一個(gè)線程,同樣執(zhí)行g(shù)etInstance方法去獲取單例對(duì)象,單例對(duì)象不為空,但是獲取到的對(duì)象確實(shí)不正確的。

這就是DCL失效問(wèn)題。

改進(jìn)的辦法是,為instance加上volatile修飾符,保證對(duì)其修改其它線程立即可見(jiàn)。

private volatile static Singleton instance = null;

雖然volatile又需要額外的性能開(kāi)銷,但是相比安全性,這個(gè)開(kāi)銷是值得的。

靜態(tài)內(nèi)部類單例模式
public class Singleton{
    private Singleton(){}
    
    public static Singleton getInstance(){
        return SingletonHolder.sInstance;
    }
    
    private static class SingletonHolder{
        private static final Singleton sInstance = new Singleton();
    }
}

根據(jù)類加載機(jī)制,對(duì)于內(nèi)部類而言,只有再需要的時(shí)候才會(huì)加載,也就是說(shuō)位于SingletonHolder中的sInstance只有在第一次調(diào)用到getInstance的時(shí)候,才會(huì)被創(chuàng)建,從而既實(shí)現(xiàn)了懶加載,也能夠確保線程安全(由JVM確保,在類加載的時(shí)候,只有一個(gè)線程會(huì)執(zhí)行類加載動(dòng)作,也就是創(chuàng)建單例對(duì)象只會(huì)由一個(gè)線程完成),推薦使用。

枚舉單例
public class EnumSingleton{
    private EnumSingleton(){}
    public static EnumSingleton getInstance(){
        return Singleton.INSTANCE.getInstance();
    }
    
    private static enum Singleton{
        INSTANCE;
        private EnumSingleton singleton;
        // 在加載的時(shí)候進(jìn)行初始化,JVM保證該方法只會(huì)被調(diào)用一次。
        private Singleton(){
            singleton = new EnumSingleton();
        }
        public EnumSingleton getInstance(){
            return singleton;
        }
    }
}

枚舉類和普通類是一樣的,但是不同的是枚舉實(shí)例的創(chuàng)建默認(rèn)是線程安全的,并且在任何情況下都是只有一個(gè)實(shí)例對(duì)象存在,即便是序列化反序列化也是。

單例模式對(duì)(反)序列化的改進(jìn)

上面所有的單例模式,除了借助枚舉來(lái)實(shí)現(xiàn)外,都存在一個(gè)缺點(diǎn),也就是第四個(gè)關(guān)鍵點(diǎn),我們需要保證單例對(duì)象在序列化和反序列化中可以保證對(duì)象的一致性,也就是不能通過(guò)反序列化違反單例的系統(tǒng)中只存在一個(gè)唯一對(duì)象的規(guī)定。

當(dāng)然,這個(gè)情況的前提是,我們的單例類實(shí)現(xiàn)了序列化接口。

通過(guò)類的readResolve函數(shù),開(kāi)發(fā)人員可以控制反序列化過(guò)程,杜絕在反序列化的時(shí)候生成新對(duì)象:

public final class Singleton implements Serializable{
    private static final long serialVersionUID = 0L;
    private static final Singleton INSTANCE = new Singleton();
    
    private Singleton(){}
    
    public static Singleton getInstance(){
        return INSTANCE;
    }
    
    private Object readResolve(){
        return INSTANCE;
    }
}

同樣的,該方法因?yàn)樾枰玫叫蛄谢?,自然是要符合序列化的要求,即?nèi)部字段也是要可序列化的。

我們將serialVersionUID置為fianl,是為了保證在修改了單例類的內(nèi)部情況的時(shí)候,反序列化也不會(huì)拋出InvalidClassException異常,只會(huì)將新修改的字段置為默認(rèn)值。

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

優(yōu)點(diǎn)在開(kāi)頭已經(jīng)說(shuō)明了,單例模式的缺點(diǎn)在于它一般沒(méi)有接口,擴(kuò)展困難,基本上修改源代碼是擴(kuò)展單例模式的唯一方法。再有,如果單例對(duì)象持有Context,很容易引發(fā)內(nèi)存泄露問(wèn)題,所以一般是用ApplicationContext。

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

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

相關(guān)文章

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

    摘要:總結(jié)單例是運(yùn)用頻率很高的模式,因?yàn)榭蛻舳藳](méi)有高并發(fā)的情況,選擇哪種方式并不會(huì)有太大的影響,出于效率考慮,推薦使用和靜態(tài)內(nèi)部類實(shí)現(xiàn)單例模式。 單例模式介紹 單例模式是應(yīng)用最廣的模式之一,也可能是很多人唯一會(huì)使用的設(shè)計(jì)模式。在應(yīng)用單例模式時(shí),單例對(duì)象的類必須保證只用一個(gè)實(shí)例存在。許多時(shí)候整個(gè)系統(tǒng)只需要一個(gè)全局對(duì)象,這樣有利于我么能協(xié)調(diào)整個(gè)系統(tǒng)整體的行為。 單例模式的使用場(chǎng)景 確保某個(gè)類有且...

    yzd 評(píng)論0 收藏0
  • JavaScript設(shè)計(jì)模式----單例模式

    摘要:不符合設(shè)計(jì)模式中的單一職責(zé)的概念。引入代理實(shí)現(xiàn)單例模式引入代理實(shí)現(xiàn)單例模式的特點(diǎn)我們負(fù)責(zé)管理單例的邏輯移到了代理類中。的單例模式對(duì)比在以上的代碼中實(shí)現(xiàn)的單例模式都混入了傳統(tǒng)面向?qū)ο笳Z(yǔ)言的特點(diǎn)。 聲明:這個(gè)系列為閱讀《JavaScript設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐》 ----曾探@著一書(shū)的讀書(shū)筆記 1.單例模式的特點(diǎn)和定義 保證一個(gè)類僅有一個(gè)實(shí)例,并且提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。 2.傳統(tǒng)面向?qū)?..

    selfimpr 評(píng)論0 收藏0
  • JavaScript設(shè)計(jì)模式-第一部分:單例模式、組合模式和外觀模式

    摘要:但是,這并不是采用單例的唯一原因。使用命名空間單例模式也被稱為模塊設(shè)計(jì)模式。函數(shù)內(nèi)部聲明了一些局部函數(shù)和或變量。緊隨函數(shù)聲明放置即可立即執(zhí)行外部函數(shù),并將所得的對(duì)象文字費(fèi)賠給變量。 JavaScript設(shè)計(jì)模式-第一部分:?jiǎn)卫J?、組合模式和外觀模式 設(shè)計(jì)模式是一些可靠的編程方式,有助于保證代碼更加易于維護(hù)、擴(kuò)展及分離,所有設(shè)計(jì)模式在創(chuàng)建大型JavaScript應(yīng)用程序時(shí)均不可或缺 單...

    betacat 評(píng)論0 收藏0
  • Java設(shè)計(jì)模式-單例模式(Singleton Pattern)

    摘要:如果需要防范這種攻擊,請(qǐng)修改構(gòu)造函數(shù),使其在被要求創(chuàng)建第二個(gè)實(shí)例時(shí)拋出異常。單例模式與單一職責(zé)原則有沖突。源碼地址參考文獻(xiàn)設(shè)計(jì)模式之禪 定義 單例模式是一個(gè)比較簡(jiǎn)單的模式,其定義如下: 保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。 或者 Ensure a class has only one instance, and provide a global point of ac...

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

    摘要:在設(shè)計(jì)模式一書(shū)中,將單例模式稱作單件模式。通過(guò)關(guān)鍵字,來(lái)保證不會(huì)同時(shí)有兩個(gè)線程進(jìn)入該方法的實(shí)例對(duì)象改善多線程問(wèn)題為了符合大多數(shù)程序,很明顯地,我們需要確保單例模式能在多線程的情況下正常工作。 在《Head First 設(shè)計(jì)模式》一書(shū)中,將單例模式稱作單件模式。這里為了適應(yīng)大環(huán)境,把它稱之為大家更熟悉的單例模式。 一、了解單例模式 1.1 什么是單例模式 單例模式確保一個(gè)類只有一個(gè)實(shí)例,...

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

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

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<