創(chuàng)建型模式(二):單例模式

介紹:

單例模式是一種創(chuàng)建型模式。它保證一個類僅有一個實例,并提供一個訪問它的全局訪問點。

類圖:

img

單例模式UML類圖.png

Singleton(單例類):定義一個getInstance操作,允許客戶訪問它的唯一實例,getInstance是一個靜態(tài)方法,主要負責創(chuàng)建自己的唯一實例。

用法:

? 確保某個類有且只有一個對象時。

個人理解:
? 創(chuàng)建一個對象需要消耗過多資源時(IO操作、訪問數(shù)據(jù)庫等)
? 工具類、幫助類( 應用程序的日志應用、接入第三方SDK等)
? 頻繁實例化然后銷毀的對象(日志、網(wǎng)絡(luò)訪問等)

例子:

單例模式是最常用的一個設(shè)計模式,常見的寫法有幾種:餓漢式懶漢式、懶漢式同步鎖雙重校驗鎖、靜態(tài)內(nèi)部類的單例模式。

1、餓漢式(線程安全、沒有懶加載)
public class Singleton{
    private static Singleton instance = new Singleton();
    private Singleton(){}

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

特點:直接在應用加載時初始化,但會浪費內(nèi)存。
解析:在類初始化時已經(jīng)初始化實例,線程安全的。

2、懶漢式(線程不安去,有懶加載)
public class Singleton{
    private static Singleton instance = null;
    private Singleton(){}

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

}

特點:單例的初始化操作,延遲到需要的時候才進行,但線程不安全。
解析:在調(diào)用getInstance()方法時才實例化,達到延遲加載的效果。

3、懶漢式同步鎖(線程安全,有懶加載)
public class Singleton {
    private static Singleton instance = null;
    private Singleton(){}
 
    public static Singleton getInstance() {
        synchronized (Singleton.class) {
            if (instance == null) {
                instance = new Singleton();
            }
        }
        return instance;
    }

}

特點:使用同步鎖synchronized保證多線程情況下單例對象的唯一性,但很多不必要的同步會影響性能。
解析:synchronized會造成不必要的同步開銷,很多情況也不需要同步,不推薦使用

4、雙重校驗鎖(線程安全,有懶加載)
public class Singleton {
    private static volatile Singleton instance = null;
    private Singleton(){}
 
    public static Singleton getInstance() {
        if (instance == null) {  //此處避免了不必要的同步
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
 
        return instance;
    }
}

特點:線程安全,避免了不必要的同步,但高并發(fā)環(huán)境下小概率會有DCL失效問題。
解析:instance = new Singleton();語句,大概做了3件事情:
(1)、給Singleton的實例分配內(nèi)存
(2)、調(diào)用Singleton()的構(gòu)造函數(shù)
(3)、將instance對象指向分配的內(nèi)存空間(instance不是null了)

但由于java編譯器允許處理器亂序執(zhí)行,執(zhí)行順序可能是 (1)-(2)-(3)或者(1)-(3)-(2)。如果是后者情況,切換到另外的線程中,instance已經(jīng)不是null了,線程B直接取走instance,再使用時就會出錯,這就是DCL失效的問題了。

5、靜態(tài)內(nèi)部類的單例模式(線程安全,有懶加載)
public class Singleton{

    private Singleton(){}

    public static Singleton newInstance(){
        return SingletonHolder.instance;
    }

    //內(nèi)部類,在裝載該內(nèi)部類時才會去創(chuàng)建單例對象
    private static class SingletonHolder{
        public static Singleton instance = new Singleton();
    }

}

特點:懶加載的同時保證線程安全,推薦使用
解析:為什么會線程安全?類的構(gòu)造器<clinit>()方法在多線程環(huán)境中被正確地加載,同步,如果多個線程同時去初始化一個類,那么只有一個線程去執(zhí)行這個類的,其他線程都需要阻塞等待,直到活動線程執(zhí)行<clinit>()方法完畢。

總結(jié):

上述幾種做法已經(jīng)滿足了絕大部分的需求,還有一些其它做法可以參考其它資料哈。

另外,單例模式需要注意內(nèi)存泄漏的問題,當一個對象已經(jīng)不需要再使用本該被回收時,另外一個正在使用的對象持有它的引用從而導致它不能被回收,產(chǎn)生了內(nèi)存泄漏。

感謝您的閱讀~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容