国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java設(shè)計模式-單例模式(Singleton Pattern)

k00baa / 2373人閱讀

摘要:如果需要防范這種攻擊,請修改構(gòu)造函數(shù),使其在被要求創(chuàng)建第二個實例時拋出異常。單例模式與單一職責(zé)原則有沖突。源碼地址參考文獻(xiàn)設(shè)計模式之禪

定義

單例模式是一個比較"簡單"的模式,其定義如下:

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

或者

Ensure a class has only one instance, and provide a global point of access to it.

確保某一個類只有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例。

請注意"簡單"二字的雙引號,說它簡單它也簡單,但是要想用好、用對其實并不那么簡單,為什么這么說?

首先,單例模式的定義比較好理解,應(yīng)用場景明確,實現(xiàn)思路比較簡單;

其次,單例模式其實要考慮的因素很多,諸如延遲加載、線程安全以及破壞單例的情況等等。也正是這些因素導(dǎo)致單例模式的實現(xiàn)方式多樣,且各有利弊

特點

單例類只能有一個實例;

單例類必須自己創(chuàng)建自己的唯一實例;

單例類必須給所有其他對象提供這一實例。

基本步驟

私有的靜態(tài)成員變量:在本類中創(chuàng)建唯一實例,使用靜態(tài)成員變量保存;為保證安全性,私有化這個成員變量

私有的構(gòu)造方法:避免其他類可以直接創(chuàng)建單例類的對象

公有的靜態(tài)方法:供其他類獲取本類的唯一實例

考慮的因素

延遲加載

線程安全

破壞單例的情況

序列化

如果Singleton類是可序列化的,僅僅在生聲明中加上implements Serializable是不夠的。為了維護(hù)并保證Singleton,必須聲明所有實例域都是瞬時(transient)的,并且提供一個readResolve方法。否則,每次反序列化一個序列化的實例時,都會創(chuàng)建一個新的對象。

反射

授權(quán)的客戶端可以通過反射來調(diào)用私有構(gòu)造方法,借助于AccessibleObject.setAccessible方法即可做到 。如果需要防范這種攻擊,請修改構(gòu)造函數(shù),使其在被要求創(chuàng)建第二個實例時拋出異常。
private Singleton() { 
        System.err.println("Singleton Constructor is invoked!");
        if (singleton != null) {
            System.err.println("實例已存在,無法初始化!");
            throw new UnsupportedOperationException("實例已存在,無法初始化!");
        }
    }
}

對象復(fù)制

在Java中,對象默認(rèn)是不可以被復(fù)制的,若實現(xiàn)了Cloneable接口,并實現(xiàn)了clone方法,則可以直接通過對象復(fù)制方式創(chuàng)建一個新對象,對象復(fù)制是不用調(diào)用類的構(gòu)造函數(shù),因此即使是私有的構(gòu)造函數(shù),對象仍然可以被復(fù)制。在一般情況下,類復(fù)制的情況不需要考慮,很少會出現(xiàn)一個單例類會主動要求被復(fù)制的情況,解決該問題的最好方法就是單例類不要實現(xiàn)Cloneable接口。

類加載器

如果單例由不同的類裝載器裝入,那便有可能存在多個單例類的實例。

實現(xiàn)方式 1、懶漢式
線程不安全(適用于單線程)
public class Singleton {
    private static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

優(yōu)點:延遲加載

缺點:線程不安全,多線程環(huán)境下有可能產(chǎn)生多個實例

為解決懶漢式"線程安全問題",可以將getInstance()設(shè)置為同步方法,于是就有了第二種實現(xiàn)方式:

線程安全
public class Singleton {
    private static Singleton singleton;

    private Singleton() {
    }

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

優(yōu)點:延遲加載,并且線程安全

缺點:效率很低,99%的情況下其實是不需要同步的

2、餓漢式
public class Singleton {
    private static Singleton singleton = new Singleton();

    private Singleton() {
    }

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

優(yōu)點:線程安全,實現(xiàn)簡單

缺點:沒有延遲加載,類加載的時候即完成初始化,可能在一定程度上造成內(nèi)存空間的浪費

如果不是特別需要延遲加載的場景,可以優(yōu)先考慮餓漢式

3、雙重檢查鎖
public class Singleton {
    private static volatile Singleton singleton;

    private Singleton() {
    }

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

優(yōu)點:延遲加載,線程安全,并且效率也很不錯

缺點:實現(xiàn)相對復(fù)雜一點,JDK1.5以后才支持volatile

說明

將同步方法改為同步代碼塊

第一個判空是為了解決效率問題,不需要每次都進(jìn)入同步代碼塊

synchronized (Singleton.class)是為了解決線程安全問題

第二個判空是避免產(chǎn)生多個實例

volatile修飾符是禁止指令重排序

這里針對volatile多說兩句,很多書上和網(wǎng)上的雙重檢查鎖實例都沒有加volatile,事實上這是不正確的

首先,volatile的兩層含義:

內(nèi)存可見性

禁止指令重排

這里我們用到的主要是第二個語義。那么什么是指令重排序呢,就是指編譯器和處理器為了優(yōu)化程序性能而對指令序列進(jìn)行排序的一種手段。簡單理解,就是編譯器對我們的代碼進(jìn)行了優(yōu)化,在實際執(zhí)行指令的的時候可能與我們編寫的順序不同,只保證程序執(zhí)行結(jié)果與源代碼相同,卻不保證實際指令的順序與源代碼相同。

singleton = new Singleton();

這段代碼在jvm執(zhí)行時實際分為三步:

在堆內(nèi)存開辟一塊內(nèi)存空間;

在堆內(nèi)存實例化Singleton

把對象(singleton)指向堆內(nèi)存空間

由于"指令重排"的優(yōu)化,很可能執(zhí)行步驟為1-3-2,即:對象并沒有實例化完成但引用已經(jīng)是非空了,也就是在第二處判空的地方為false,直接返回singleton——一個未完成實例化的對象引用。

這里涉及到Java內(nèi)存模型、內(nèi)存屏障等知識點,本文主要介紹單例模式,因此不再贅述,有興趣的同學(xué)可以自行百度

4、靜態(tài)內(nèi)部類
public class Singleton {
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    private Singleton() {
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

與餓漢式的區(qū)別是,靜態(tài)內(nèi)部類SingletonHolder只有在getInstance()方法第一次調(diào)用的時候才會被加載(實現(xiàn)了延遲加載效果)。

因此靜態(tài)內(nèi)部類實現(xiàn)方式既能保證線程安全,也能保證單例的唯一性,同時也具有延遲加載特性

5、枚舉
public enum  Singleton {
    INSTANCE;
    public void doSomething() {
        System.out.println("doSomething");
    }
}

優(yōu)點:枚舉方式具有以上所有實現(xiàn)方式的優(yōu)點,同時還無償?shù)靥峁┝诵蛄谢瘷C(jī)制,防止多次實例化

缺點:JDK1.5以后才支持enum;普及度較前幾種方式不高

優(yōu)點

由于單例模式在內(nèi)存中只有一個實例,減少了內(nèi)存開支,特別是一個對象需要頻繁地創(chuàng)建、銷毀時,而且創(chuàng)建或銷毀時性能又無法優(yōu)化,單例模式的優(yōu)勢就非常明顯。

由于單例模式只生成一個實例,所以減少了系統(tǒng)的性能開銷,當(dāng)一個對象的產(chǎn)生需要比較多的資源時,如讀取配置、產(chǎn)生其他依賴對象時,則可以通過在應(yīng)用啟動時直接產(chǎn)生一個單例對象,然后用永久駐留內(nèi)存的方式來解決(在Java EE中采用單例模式時需要注意JVM垃圾回收機(jī)制)。

單例模式可以避免對資源的多重占用,例如一個寫文件動作,由于只有一個實例存在內(nèi)存中,避免對同一個資源文件的同時寫操作。

單例模式可以在系統(tǒng)設(shè)置全局的訪問點,優(yōu)化和共享資源訪問,例如可以設(shè)計一個單例類,負(fù)責(zé)所有數(shù)據(jù)表的映射處理。

缺點

單例模式一般沒有接口,擴(kuò)展很困難,若要擴(kuò)展,除了修改代碼基本上沒有第二種途徑可以實現(xiàn)。單例模式為什么不能增加接口呢?因為接口對單例模式是沒有任何意義的,它要求“自行實例化”,并且提供單一實例、接口或抽象類是不可能被實例化的。當(dāng)然,在特殊情況下,單例模式可以實現(xiàn)接口、被繼承等,需要在系統(tǒng)開發(fā)中根據(jù)環(huán)境判斷。

單例模式對測試是不利的。在并行開發(fā)環(huán)境中,如果單例模式?jīng)]有完成,是不能進(jìn)行測試的,沒有接口也不能使用mock的方式虛擬一個對象。

單例模式與單一職責(zé)原則有沖突。一個類應(yīng)該只實現(xiàn)一個邏輯,而不關(guān)心它是否是單例的,是不是要單例取決于環(huán)境,單例模式把“要單例”和業(yè)務(wù)邏輯融合在一個類中。

使用場景

在一個系統(tǒng)中,要求一個類有且僅有一個對象,如果出現(xiàn)多個對象就會出現(xiàn)“不良反應(yīng)”,可以采用單例模式,具體的場景如下:

要求生成唯一序列號的環(huán)境;

在整個項目中需要一個共享訪問點或共享數(shù)據(jù),例如一個Web頁面上的計數(shù)器,可以不用把每次刷新都記錄到數(shù)據(jù)庫中,使用單例模式保持計數(shù)器的值,并確保是線程安全的;

創(chuàng)建一個對象需要消耗的資源過多,如要訪問IO和數(shù)據(jù)庫等資源;

需要定義大量的靜態(tài)常量和靜態(tài)方法(如工具類)的環(huán)境,可以采用單例模式(當(dāng)然,也可以直接聲明為static的方式)。

源碼地址:https://gitee.com/tianranll/j...

參考文獻(xiàn):《設(shè)計模式之禪》、《Effective Java》

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/77739.html

相關(guān)文章

  • Java23種設(shè)計模式與J2EE設(shè)計模式

    摘要:這個模式感覺一一般和工廠模式一起使用的比較多比較方便結(jié)構(gòu)型模式這些設(shè)計模式關(guān)注類和對象的組合。設(shè)計模式這些設(shè)計模式特別關(guān)注表示層。 設(shè)計模式的的六大原則: 學(xué)習(xí)設(shè)計模式之前最好先了解一下設(shè)計模式的設(shè)計原則: 1. 開閉原則(open close principle) 開放即指對擴(kuò)展開放,對修改關(guān)閉 簡而言之,就是擴(kuò)展功能的時候應(yīng)該盡量的不修改原有的代碼。 2. 里氏代換原則(lisko...

    andot 評論0 收藏0
  • 設(shè)計模式: 從ES5 到 TypeScript ——單例模式

    摘要:現(xiàn)在讓我們設(shè)置溫度值并將其增加減少幾次小結(jié)在中,單例模式根據(jù)是否懶漢模式餓漢模式以及是否線程安全,分為很多種實現(xiàn)方式。參考設(shè)計模式與開發(fā)實踐設(shè)計模式 Back in 1994, a book was authored by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides that discusses 23 desg...

    王軍 評論0 收藏0
  • #yyds干貨盤點#設(shè)計模式之【單例模式

    摘要:枚舉推薦優(yōu)點懶加載,線程安全,效率高,大牛推薦作者推薦總結(jié)關(guān)于單例模式的實現(xiàn)方式,首推的就是枚舉,其次是懶漢模式雙重檢查,最后是靜態(tài)內(nèi)部類 作者:湯圓個人博客:javalover.cc前言有時候我們的類并不需要很多個實例,在程序運行期間,可能只需要一個實例就夠了,多了反而會出現(xiàn)數(shù)據(jù)不一致的問題;這時候我們就可以...

    sourcenode 評論0 收藏0
  • Design Pattern - Singleton Pattern(譯)

    摘要:創(chuàng)建的對象使構(gòu)造函數(shù)私有,外界將無法實例化該類獲得唯一可用的對象第二步從單例類獲得唯一的對象。非法構(gòu)造編譯錯誤,構(gòu)造函數(shù)不可見。獲得唯一可用對象展示信息第三步校驗輸出。 原文鏈接譯者:smallclover個人翻譯,水平有限,如有錯誤歡迎指出,謝謝! 設(shè)計模式-單例模式 單例模式是Java中最簡單的設(shè)計模式之一。這種類型的設(shè)計模式,是創(chuàng)建型模式下創(chuàng)建對象的最好方式之一。這個模式涉及到一...

    yck 評論0 收藏0
  • 設(shè)計模式-單例模式

    摘要:簡介最基本的實例中規(guī)定了一個類只會被初始化一次所以該方法是線程安全的但是其在方法調(diào)用前就初始化了比較浪費資源優(yōu)點只有一個實例節(jié)約內(nèi)存空間減少了系統(tǒng)的性能開銷如果某一個對象的產(chǎn)生需要比較多的資源時可以在啟動時直接產(chǎn)生一個單例對象使其永駐內(nèi)存可 In software engineering, the singleton pattern is a software design patte...

    guqiu 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<