Java設計模式——單例模式

單例模式由于只創(chuàng)建了唯一對象可以避免資源的多重占用,減少內(nèi)存的開銷,對于經(jīng)常性使用對象的類來說,單例是一個不錯的選擇,使用場景,比如:文件操作、共享資源等等。

1、餓漢單例模式

這是最為簡單的也是最基本的單例模式,相信大家都寫過!先上代碼:

public class Single{
   private static final Single instance = new Single();
    private Single(){}
    public static Single getInstance(){
        return instance;
    }
}

由于把構(gòu)造函數(shù)變?yōu)榱藀rivate,所以要想獲得該類的實例需要通過getInstance(),而不是手動去new一個,這僅僅是最為簡單粗暴的單例模式。

2、懶漢單例模式

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

懶漢單例模式看起來和餓漢單例模式差不多,就多了一個 synchronized 關鍵字,也就是說該模式是同步的方法單例。在 getInstanc()方法中,可以清楚知道不管該類對象是否已經(jīng)實例了(實際上第一次調(diào)用的時候只new了一次),都會進行同步,這樣確實每次都同步確實耗費了不必要的資源和內(nèi)存,而且在加載的時候都會事先 synchronized,所以會比較耗時間,所以不太建議使用。

3、Double Check Lock(DCL)

public class Single{
    
    private static Single instance = null;
    private Single(){}
    public static Single getInstance(){
        if (instance == null){
            synchronized (Single.class){
                if (instance == null){
                    instance = new Single();
                }
            }
        }
        return instance;
    }
}

在代碼中可以看到,在調(diào)用 getInstance() 方法的時候會檢查類的實例是否為空,true則直接返回該實例,false則會 synchronized (利用Single.class來對本類對象同步),如果為null則會new一個對象,否則直接返回。這意思很清楚,這里有兩次判斷是否為null的步驟,第一步判斷是為了避免不必要的同步,而第二步則是同步檢查。
??我們知道在new,即instance = new Single()的時候,一般會有三個步驟:1、分配內(nèi)存;2、調(diào)用構(gòu)造函數(shù)并初始化成員字段;3、為對象指向分配好的空間。而Java是允許處理器亂序執(zhí)行的,還有JDK版本原因,很多時候這三個步驟很可能不是按照順序執(zhí)行的,
所以在多線程的操作下,如果在A線程中執(zhí)行某一步的時候,B線程也調(diào)用了該方法,而這時候A線程剛剛好分配內(nèi)存成功(假設第一個調(diào)用)但未調(diào)用構(gòu)造函數(shù)創(chuàng)建對象,所以這時候B在檢查的時候?qū)ο笠呀?jīng)非空了(因為已經(jīng)指向了內(nèi)存),所以B線程會直接使用對象instance,很顯然,由于還沒調(diào)用構(gòu)造函數(shù),所以B線程使用的時候會出問題。這叫DCL失效。雖然說這是很小的概率問題,但還是會長期隱藏著問題的。不過從JDK1.5之后,sun注意了這個問題,把這個bug修改了過來,只要 如此聲明:private volatile static Single instance = null 就可以保證instance 是從主內(nèi)存取出來的,雖然volatile 會影響性能,但為了DCL有效就值得。
??總的來說DCL是餓漢、懶漢單例模式的結(jié)合,盡管存在bug,但還是sun已修改了,所以比較建議這種寫法。

4 、內(nèi)部靜態(tài)類單例模式

??利用靜態(tài)內(nèi)部類的特性來返回對象(static關鍵字不用多講了吧)

public class Single {

    private Single (){}
    public static Single getInstance(){
        return SingleHolder.instance;
    }
    private static class SingleHolder{
        private static final Single  instance = new Single();
    }

}

??這不僅僅首次調(diào)用才初始化,而且線程安全,也能保證對象的唯一性,所以這也是推薦的寫法。

5、枚舉單例模式

public enum  SingleEnum {
    INSTANCE;
}

在Java中,枚舉類型是默認線程安全的,在任何情況下都能保證唯一性,而且寫法最為簡單。大家可以嘗試一下的

6、容器單例模式

public class SingleCollect {
    private static Map<String, Object> objectMap = new HashMap<>();
    private SingleCollect(){}

    /**
     * 根據(jù)類名把實例通過Map保存起來
     * @param key  類名
     * @param instance  類的實例對象
     */
    public static void registInatance(String key, Object instance){
        if (!objectMap.containsKey(key)){
            objectMap.put(key, instance);
        }
    }

    /**
     * 根據(jù)類名來尋找對應的對象實例
     * @param key
     * @return
     */
    public static Object getInstance(String key){
        return objectMap.get(key);
    }
}

??利用Map把類的對象實例保存起來,在需要的時候根據(jù)類名key獲取即可。

總結(jié)

??通過幾種單例模式,核心思想無非是把構(gòu)造函數(shù)私有化,然后利用 public static修飾符來獲取對象實例,并且保證線程安全?。?!值得注意的時候,我們還需要考慮這么一種情況:反序列化。我們知道可以通過序列化把對象實例寫進磁盤,然后再讀回來。而反序列化依然可以通過別的途徑去重新創(chuàng)建一個新的對象實例,即便是私有的構(gòu)造函數(shù)!上述的幾種模式就只有枚舉單例模式可以避免。不過,在實際開發(fā)中,我們需要結(jié)合項目需要,而不是一味地直接使用枚舉單例模式,靈活使用單例模式才是正道。
??上文如有不對或者不妥之處,大家記得留言指出哈。一起進步才比較爽啊?。?!and then 后續(xù)我會繼續(xù)寫一系列關于設計模式的,請大家靜候!

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

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

  • 單例模式(SingletonPattern)一般被認為是最簡單、最易理解的設計模式,也因為它的簡潔易懂,是項目中最...
    成熱了閱讀 4,530評論 4 34
  • 概念 java中單例模式是一種常見的設計模式,單例模式的寫法有好幾種,比較常見的有:懶漢式單例、餓漢式單例。單例模...
    怡紅快綠閱讀 538評論 0 0
  • Java設計模式——單例模式 單例模式應該是大家最為熟知的一種設計模式了,相信大家或多或少的都在自己的項目中使用過...
    gogoingmonkey閱讀 571評論 0 2
  • 今天筆試的時候被問到了單例模式,聽了很多次,但是卻沒有認真看過,所以交了白卷,懶的教訓啊!還有一題比較有趣的題目:...
    shakesbears閱讀 420評論 0 3
  • 閱讀原文 在介紹單例模式之前,我們先了解一下,什么是設計模式?設計模式(Design Pattern):是一套被反...
    gyl_coder閱讀 212評論 0 3

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