2--∞:?jiǎn)卫J剑⊿ingleton Pattern)

前言

此篇文章只是本人學(xué)習(xí) 單列模式(Singleton Pattern) 使用的筆記,如有雷同,純屬緣分!

什么是單例?

單例模式(Singleton Pattern):確保某一個(gè)類只有一個(gè)實(shí)例,并提供該實(shí)例的全局訪問,其構(gòu)造函數(shù)私有化。它是 Java 中最簡(jiǎn)單的設(shè)計(jì)模式(Design Pattern)。

設(shè)計(jì)模式(Design Pattern):前人對(duì)特定問題經(jīng)過無數(shù)次的經(jīng)驗(yàn)總結(jié)之后 ,提出的能夠解決它的優(yōu)雅的方案。它不是一種技術(shù)與方法,而是一種思想!

本質(zhì):

控制實(shí)例數(shù)量

三大要點(diǎn):

線程安全
延遲加載
序列化與反序列化安全

單例的幾種寫法

1.餓漢式
public class Singleton {
    //上去就是干,直接實(shí)例化
    private static Singleton instances = new Singleton();
    //私有化構(gòu)造函數(shù),阻止實(shí)例化對(duì)象
    private Singleton() {}
    //直接返回已經(jīng)實(shí)例化了的對(duì)象
    public static Singleton getInstances() {
        return instances;
    }
    public void doSomething() {
        //doSomething....
    }
}

餓漢式 這種實(shí)現(xiàn)單例方法是最簡(jiǎn)單粗暴的,它在類開始加載時(shí)就初始化了(但浪費(fèi)內(nèi)存),而且在多線程中是安全的,是典型的空間換時(shí)間。如果單例對(duì)象初始化非常快,而且占用內(nèi)存非常小的時(shí)候,用這種方式是比較合適的,可以直接在應(yīng)用啟動(dòng)時(shí)加載并初始化。

2.懶漢式,線程不安全
public class Singleton {
    private static Singleton instances = null;
    private Singleton() {}
    //如果發(fā)現(xiàn)沒有實(shí)例對(duì)象,就構(gòu)造一個(gè);如果有實(shí)例對(duì)象,直接返回
    public static Singleton getInstances() {
        if (instances == null) {
            instances = new Singleton();
        }
        return instances;
    }
    public void doSomething() {
        //doSomething
    }
}

懶漢式 就是將單例的初始化操作,延遲加載 到需要的時(shí)候才進(jìn)行,這樣做在某些場(chǎng)合中有很大用處。比如某個(gè)單例用的次數(shù)不是很多,但是這個(gè)單例提供的功能又非常復(fù)雜,而且加載和初始化要消耗大量的資源,這個(gè)時(shí)候使用懶漢式就是非常不錯(cuò)的選擇。但它在 多線程中不安全(比如,有兩個(gè)線程,一個(gè)是線程 A,一個(gè)是線程 B,它們同時(shí)調(diào)用 getInstances 方法,就可能導(dǎo)致并發(fā)問題),是典型的時(shí)間換空間

3.懶漢式,線程安全
public class Singleton {
    private static Singleton instances = null;
    private Singleton() {}
    public static Singleton getInstances() {
        //加入同步鎖 synchronized
        synchronized (Singleton.class) {
            if (instances == null) {
                instances = new Singleton();
            }
            return instances;
        }
    }
    public void doSomething() {
        //doSomething
    }
}

這種是最常見的解決同步問題的一種方式,使用同步鎖 **synchronized (Singleton.class) **防止多線程同時(shí)進(jìn)入造成 getInstances 被多次實(shí)例化。

4.懶漢式,雙重校驗(yàn)鎖
public class Singleton {
    // 對(duì)保存實(shí)例的變量添加 volitile 的修飾
    private volatile static Singleton instances = null;
    private Singleton(){}
    public static Singleton getInstances(){
        //先檢查實(shí)例是否存在,如果不存在才進(jìn)入下面的同步塊
        if(instances == null){
            //同步塊,線程安全的創(chuàng)建實(shí)例
            synchronized (Singleton.class) {
                //再次檢查實(shí)例是否存在,如果不存在才真正的創(chuàng)建實(shí)例
                if (instances == null){
                    instances = new Singleton();
                }
            }
        }
        return instances;
    }
    public void doSomething() {
        //doSomething
    }
}

雙重校驗(yàn)鎖 指的是:并不是每次進(jìn)入 getInstances 方法都需要同步,而是先不同步,進(jìn)入方法過后,先檢查實(shí)例是否存在,如果不存在才進(jìn)入下面的同步塊,這是第一重檢查。進(jìn)入同步塊后,再次檢查實(shí)例是否存在,如果不存在,就在同步的情況下創(chuàng)建一個(gè)實(shí)例。這是第二重檢查。

雙重加鎖機(jī)制的實(shí)現(xiàn)會(huì)使用一個(gè)關(guān)鍵字 volatile ,它的意思是:被 volatile 修飾的變量的值,將不會(huì)被本地線程緩存,所有對(duì)該變量的讀寫都是直接操作共享內(nèi)存,從而確保多個(gè)線程能正確的處理該變量。

5.靜態(tài)內(nèi)部類
public class Singleton {
    //類級(jí)的內(nèi)部類,也就是靜態(tài)類的成員式內(nèi)部類,該內(nèi)部類的實(shí)例與外部類的實(shí)例
    //沒有綁定關(guān)系,而且只有被調(diào)用時(shí)才會(huì)裝載,從而實(shí)現(xiàn)了延遲加載
    private static class SingletonHolder {
        //靜態(tài)初始化器,由JVM來保證線程安全
        private static Singleton instances = new Singleton();
    }
    private Singleton() {}
    public static Singleton getInstances() {
        return SingletonHolder.instances;
    }
    public void doSomething() {
        //doSomething
    }
}

這樣實(shí)現(xiàn)出來的單例類就是線程安全的,而且使用起來非常簡(jiǎn)潔。

6.枚舉類型單例模式
public enum Singleton{
    //定義一個(gè)枚舉的元素,它就是Singleton的一個(gè)實(shí)例
    instance;
    public void doSomething(){
        // do something ...
    }    
}

這種方法是根據(jù) Effective Java 書中的說法,默認(rèn)枚舉實(shí)例的創(chuàng)建是 線程安全 的.(創(chuàng)建枚舉類的單例在 JVM 層面也是能保證線程安全的), 所以不需要擔(dān)心線程安全的問題,所以理論上枚舉類來實(shí)現(xiàn)單例模式是最簡(jiǎn)單的方式。

總結(jié)

以上就是 單例模式 的幾種寫法。分別是餓漢懶漢同步鎖雙重校驗(yàn)鎖靜態(tài)內(nèi)部類枚舉。我們可以根據(jù)不同的場(chǎng)景選擇最喜歡的一種單例模式吧!

如何使用

當(dāng)需要控制一個(gè)類的實(shí)例只能有一個(gè),而且客戶只能從一個(gè)全局訪問點(diǎn)訪問它時(shí),可以選用單例模式,這些功能恰好是單例模式要解決的問題

番外閱讀

單例模式的一些注意點(diǎn)

參考

ANDROID設(shè)計(jì)模式之單例模式
設(shè)計(jì)模式干貨系列:(四)單例模式【學(xué)習(xí)難度:★☆☆☆☆,使用頻率:★★★★☆】

                                        -- 默默的劃水ing--
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容