簡(jiǎn)單易懂設(shè)計(jì)模式 之 單例(Singleton)

one.jpg

單例模式概念并不復(fù)雜,其核心在于這個(gè)“單”字,全局只有一個(gè),無(wú)法創(chuàng)建多余一個(gè)的實(shí)例;單例模式在實(shí)際使用中很常見(jiàn),是一種簡(jiǎn)單卻實(shí)用的設(shè)計(jì)模式

使用場(chǎng)景

什么時(shí)候需要用到單例模式呢?我認(rèn)為主要有兩種情況

  1. 最好只有一個(gè)實(shí)例,即某個(gè)類在全局中只需要一個(gè)實(shí)例即可滿足需求,再創(chuàng)建多余的實(shí)例既無(wú)必要,也浪費(fèi)資源,如一個(gè)全局的日志類,或者Spring管理下的Bean默認(rèn)也是單例
  2. 應(yīng)該只有一個(gè)實(shí)例,即某個(gè)類的實(shí)例不應(yīng)該超過(guò)一個(gè),否則有可能會(huì)產(chǎn)生問(wèn)題,如一個(gè)數(shù)據(jù)庫(kù)連接池,全局就只應(yīng)該只有一個(gè)

總體來(lái)說(shuō),當(dāng)某個(gè)類的實(shí)體類最好或應(yīng)該只有一個(gè)實(shí)例的時(shí)候,就應(yīng)該考慮使用單例模式進(jìn)行代碼組織

代碼示例

單例模式比較常用的形式有兩種:饑漢模式與懶漢模式。這兩種模式的共同點(diǎn)在于都是通過(guò)私有化構(gòu)造方法來(lái)限制實(shí)例的創(chuàng)建,它們的主要區(qū)別在于實(shí)例是預(yù)加載還是懶加載,一般來(lái)說(shuō)建議使用懶加載的形式,畢竟有助于節(jié)省資源,提升效率;另外還有一種創(chuàng)建單例的形式,大家可能經(jīng)常會(huì)用到,但不一定意識(shí)到自己其實(shí)寫了個(gè)單例,那就是Java的枚舉,首先枚舉沒(méi)有課訪問(wèn)的構(gòu)造器,另外枚舉是通過(guò)公有的靜態(tài)final域?yàn)槊總€(gè)枚舉常量導(dǎo)出實(shí)例的類,這句話是什么意思呢?注意幾個(gè)重要的詞:靜態(tài),final實(shí)例的類,其實(shí)意思就是說(shuō)每個(gè)枚舉常量都是一個(gè)靜態(tài)且final的類的實(shí)例,我想寫到這里大家應(yīng)該很容易能理解為什么說(shuō)枚舉也是單例了,而且是一個(gè)final static的單例

  1. 饑漢模式(預(yù)加載)
public class EagerSingleton {
     private static EagerSingleton instance = new EagerSingleton();
    
     private EagerSingleton(){}
    
     public static EagerSingleton getInstance() {
          return instance;
     }
}
  1. 懶漢模式DCL版(懶加載)
public class LazySingleton {
     private volatile static LazySingleton instance;
    
     private LazySingleton(){}
    
     public static LazySingleton getInstance() {
          if(instance == null){
               synchronized(LazySingleton.class){
                    if(instance == null){
                         instance = new LazySingleton();
                    }
               }
          }
          return instance;
     }
}

在上述代碼示例的懶漢模式中,使用了DCL(Double checked Locking),個(gè)人認(rèn)為這其實(shí)是一種不好的形式,假如不在instance實(shí)例前增加volatile聲明,那么將有可能會(huì)導(dǎo)致錯(cuò)誤,即會(huì)導(dǎo)致:unsafe publication,什么意思呢,即在第一次check時(shí),即便instance不是空,但是也有可能此時(shí)的instance還未初始化完全,數(shù)據(jù)是不完整的,或錯(cuò)的,而使用volatile在java 5.0之后雖然確實(shí)能避免這樣的問(wèn)題,但是使得代碼形式顯得比較繁瑣,同時(shí)DCL的主要目的在于盡量減少同步帶來(lái)的性能損耗,殊不知這種優(yōu)化基本可以忽略不計(jì),所以我建議一般采用下面簡(jiǎn)單的寫法即可

  1. 懶漢模式簡(jiǎn)化版(懶加載)
public class RegularSingleton {
    private static RegularSingleton instance;

    private RegularSingleton(){}

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

一個(gè)synchronized關(guān)鍵字即可,不需要volatile,亦不需DCL

  1. 枚舉型單例
public enum ManKind {
    MAN {
        @Override
        void sad() {
            System.out.println("get a sleep");
        }
    },
    WOMAN {
        @Override
        void sad() {
            System.out.println("shopping");
        }
    };

    abstract void sad();
}

應(yīng)用實(shí)例

在JDK源碼中有很多對(duì)單例模式的使用,這里列舉幾個(gè)大家有興趣可以閱讀一下

  1. java.lang.Runtime#getRuntime()
  2. java.awt.Desktop#getDesktop()
  3. java.lang.System#getSecurityManager()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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