單例設(shè)計(jì)模式

單例設(shè)計(jì)模式是用的最多的設(shè)計(jì)模式,也是最簡單的一中設(shè)計(jì)模式。下面來介紹下幾種實(shí)現(xiàn)單例的方式,以及分析下各自的優(yōu)缺點(diǎn)。

餓漢式


    public  class CEO {
        private static final CEO instance = new CEO();

        private CEO() {
        }

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

構(gòu)造函數(shù)私有,利用共有的靜態(tài)函數(shù),對外暴露獲取單例對象的接口。CEO對象在聲明的時(shí)候就初始化了,并且是靜態(tài)的。這樣就保證了對象的唯一性。

懶漢式

 public  class Singleton {
        private static Singleton instance = null;

        private Singleton() {
        }

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

與餓漢式的區(qū)別是靜態(tài)對象在第一次調(diào)getInstance()時(shí)進(jìn)行初始化。
synchronized確保getInstance()是個(gè)同步方法,用來確保在多線程情況下單例的唯一性。
優(yōu)點(diǎn):只有在使用時(shí)才被初始化,節(jié)約資源
弊端:每次調(diào)用getInstance()都需要同步,造成不必要的同步開銷

Double Check Lock(DCL)實(shí)現(xiàn)單例

這種模式其實(shí)是對懶漢式的優(yōu)化,將鎖放到內(nèi)部,當(dāng)?shù)谝淮纬跏蓟瘑卫臅r(shí)候才同步:

 public  class Singleton {
        private static Singleton instance = null;

        private Singleton() {
        }

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

上面進(jìn)行2次判空:
第一次是為了避免不必要的同步
第二次是為了在null的情況下創(chuàng)建實(shí)例
為什么要進(jìn)行第二次判空呢?
我們看下instance = new Singleton()這步會(huì)做什么:
1、給Singleton的實(shí)例分配內(nèi)存;
2、調(diào)用Singleton()的構(gòu)造函數(shù),初始化成員字段;
3、將instance對象指向分配的內(nèi)存空間(這樣instance就不是null了)
但是JDK1.5之前并不能保證第二步和第三步的順序,如果先走的3,那么此時(shí)如果有另外個(gè)線程getInstance()那么它就可以直接獲取單例對象,當(dāng)他使用的時(shí)候就會(huì)出錯(cuò)。
JDK1.5之后只需要將instance第一為private volatile static Singleton instance = null;這樣就行。添加關(guān)鍵字volatile保證instance每次都是從主內(nèi)存中讀取。

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

DCL雖然了資源消耗、多余同步、線程安全等問題,但是在某些并發(fā)情況下會(huì)失效,因此并步推薦使用DCL。
下面這種通過靜態(tài)內(nèi)部類實(shí)現(xiàn)單例的方法是推薦使用的

   public  class Singleton {


        private Singleton() {
        }

        /**
         * 靜態(tài)內(nèi)部類
         */
        private static class SingletonHolder {
            private static final Singleton instance = new Singleton();
        }

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

1、instance只有在調(diào)getInstance()的時(shí)候才初始化
2、通過靜態(tài)內(nèi)部類不僅能確保線程安全,也能保證單例的唯一性

枚舉單例

其實(shí)考慮到唯一性和線程安全性的時(shí)候我就應(yīng)該想到枚舉,下面我們通過枚舉來實(shí)現(xiàn)單例

public enum Singleton {
        SINGLETON;
    }

先不說性能,至少這是實(shí)現(xiàn)單例最簡單的方法。
枚舉的好處是默認(rèn)枚舉實(shí)例的創(chuàng)建是線程安全的,并且任何情況下它都是一個(gè)單例。
之前幾種方法都會(huì)存在一個(gè)問題,就是在反序列化時(shí),可能創(chuàng)建一個(gè)新的實(shí)例

總結(jié)

不管哪種形式實(shí)現(xiàn)單例,核心原理就是將構(gòu)造函數(shù)私有化,并通過靜態(tài)方法獲取唯一的實(shí)例。在獲取這個(gè)實(shí)例的過程中要保證線程安全、唯一性等問題

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

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

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