設(shè)計(jì)模式之單件模式(Singleton Pattern)

單件模式,也叫單例模式,可以說(shuō)是設(shè)計(jì)模式中最簡(jiǎn)單的一種。顧名思義,就是創(chuàng)造獨(dú)一無(wú)二的唯一的一個(gè)實(shí)例化的對(duì)象。

為什么要這樣做呢?因?yàn)橛行r(shí)候,我們只需要一個(gè)對(duì)象就夠了,太多對(duì)象反而會(huì)引起不必要的麻煩。比如說(shuō),線程池,緩存,打印機(jī),注冊(cè)表,如果存在多個(gè)實(shí)例的話,反而會(huì)導(dǎo)致許多問(wèn)題!

引出單例模式

我們通過(guò)一個(gè)小問(wèn)題引出單例模式!

  • 如何創(chuàng)建一個(gè)對(duì)象?我們都知道 new MyObject();
  • 當(dāng)我們需要?jiǎng)?chuàng)建與另外一個(gè)對(duì)象時(shí),只需要再次new MyObject();即可
  • 那么如下這樣的代碼是正確的么?
public MyClass{
  private MyClass() {}  
}
  • 看過(guò)去這是合法的定義,沒(méi)有什么語(yǔ)法錯(cuò)誤。但仔細(xì)想想,含有私有構(gòu)造器的話,只能在MyClass內(nèi)調(diào)用構(gòu)造器。因?yàn)楸仨氂蠱yclass的實(shí)例才能調(diào)用構(gòu)造器,但因?yàn)闆](méi)有其他類可以取得它的實(shí)例,所以,我們無(wú)法實(shí)例化它,這像不像雞生蛋還是蛋生雞的問(wèn)題?哈哈哈
  • 為了解決這個(gè)問(wèn)題,取得MyClass類的實(shí)例,我們創(chuàng)造一個(gè)靜態(tài)方法
public MyClass{
  private MyClass() {}  
  public static MyClass getInstance() {
    return new MyClass();
  }
}
  • 我們添加了一個(gè)靜態(tài)的類方法,它可以返回一個(gè)對(duì)象實(shí)例,由于他是public,所以外部可以調(diào)用他。這實(shí)際上就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的單例模式。

經(jīng)典單例模式的實(shí)現(xiàn)

public class Singleton {
    private static Singleton uniqueInstance;
    
    private Singleton(){}
    
    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    } 
}
  • 這里實(shí)現(xiàn)了一個(gè)概念,叫延遲實(shí)例化(lazy instance)。因?yàn)樵谖覀儾恍枰獙?shí)例的時(shí)候,這個(gè)實(shí)例就永遠(yuǎn)不會(huì)被實(shí)例化。

定義單件模式

單件模式的定義: 確保一個(gè)類只有一個(gè)實(shí)例,并提供一個(gè)全局訪問(wèn)點(diǎn)。

這定義應(yīng)該很好理解,我們結(jié)合類圖說(shuō)明:

Paste_Image.png

經(jīng)典單件模式存在的問(wèn)題

經(jīng)典單件模式實(shí)際中存在這一定的問(wèn)題,在第一次初始化實(shí)例的時(shí)候,如果同時(shí)有不同的線程訪問(wèn),那么可能最后不只實(shí)例化出一個(gè)對(duì)象。

Paste_Image.png

如圖所示,如果兩個(gè)線程如圖所示的順序交錯(cuò)執(zhí)行,那么最后會(huì)實(shí)例化兩個(gè)對(duì)象!
這就是經(jīng)典單例模式存在的多線程問(wèn)題。

解決單例模式的多線程問(wèn)題

synchronize

顯然最簡(jiǎn)單的一種解決方法就是同步getInstance方法。

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

這樣顯然可以很好的解決問(wèn)題,但是同步會(huì)降低效率。

急切實(shí)例化

public class Singleton {
    private static Singleton uniqueInstance = new Singleton();
    
    private Singleton(){}
    
    public static synchronized Singleton getInstance() {
        return uniqueInstance;
    } 
}

在任何線程訪問(wèn)uniqueInstance變量前,我們保證一定已經(jīng)創(chuàng)建了這個(gè)實(shí)例。

雙重檢查加鎖

public class Singleton {
    private volatile static Singleton uniqueInstance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            synchronized (Singleton.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}
最后編輯于
?著作權(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)容