單例模式

1.定義

單例模式是確保全局只有一個實例悲幅,并且提供一個全局的訪問點煎饼,屬于創(chuàng)建型模式廉嚼,典型應(yīng)用就是枚舉

2.餓漢式單例模式

餓漢式單例模式在類加載的時候就已經(jīng)創(chuàng)建,屬于線程安全模式告组,因為那個時候還沒有線程,在線程出現(xiàn)以前就已經(jīng)實例化了癌佩,代碼:

/**
 * 優(yōu)點:執(zhí)行效率高木缝,性能高,沒有任何的鎖
 * 缺點:某些情況下围辙,可能會造成內(nèi)存浪費
 * create by yufeng on 2021/7/3 21:00
 */
public class HungrySingleton {

    private static final HungrySingleton hungrySingleton = new HungrySingleton();

    private HungrySingleton(){}

    public static HungrySingleton getInstance(){
        return  hungrySingleton;
    }
}

/**
 * 靜態(tài)代碼塊的形式
 * create by yufeng on 2021/7/3 21:00
 */
public class HungryStaticSingleton {

    private static final HungryStaticSingleton hungrySingleton;


    static {
        hungrySingleton = new HungryStaticSingleton();
    }

    private HungryStaticSingleton(){}

    public static HungryStaticSingleton getInstance(){
        return  hungrySingleton;
    }
}
3.懶漢式單例模式

為了餓漢模式帶來的內(nèi)存浪費問題我碟,就弄了個懶漢模式,因為只有在被用到的時候才會被實例化姚建,所以就避免了內(nèi)存浪費的問題


/**
 * 優(yōu)點:節(jié)省了內(nèi)存,線程安全
 * 缺點:性能低
 * create by yufeng on 2021/7/3 21:12
 */
public class LazySimpleSingletion {
    private static LazySimpleSingletion instance;
    private LazySimpleSingletion(){}

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

為了解決上面性能低的問題矫俺,用雙重檢查鎖的方法:
  /**
 * 優(yōu)點:性能高了,線程安全了
 * 缺點:可讀性難度加大掸冤,不夠優(yōu)雅
 * create by yufeng on 2021/7/3 21:12
 */
public class LazyDoubleCheckSingleton {
    private volatile static LazyDoubleCheckSingleton instance;
    private LazyDoubleCheckSingleton(){}

    public static LazyDoubleCheckSingleton getInstance(){
        //檢查是否要阻塞
        if (instance == null) {
            synchronized (LazyDoubleCheckSingleton.class) {
                //檢查是否要重新創(chuàng)建實例
                if (instance == null) {
                    instance = new LazyDoubleCheckSingleton();
                    //指令重排序的問題
                }
            }
        }
        return instance;
    }
}

但是第二種寫法還是有鎖的問題厘托,存在性能的問題,這個時候就用內(nèi)部類的形式來解決

/*
  兼顧了餓漢模式的浪費內(nèi)存稿湿,和懶漢模式鎖性能的問題
   create by yufeng on 2021/7/3 21:12
 */
public class LazyInnerClassSingleton {

  // 使用的時候默認先加載內(nèi)部類
    private LazyInnerClassSingleton(){
    }

    private static final LazyInnerClassSingleton getInstance(){
        return LazyHolder.LAZY;
    }

  // 默認不加載
    private static class LazyHolder{
        private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton();
    }

}
    

但是上面的方法還是可以通過反射進行破壞單例模式铅匹,所以在上面的基礎(chǔ)實例化前加個校驗

/*
  ClassPath : LazyStaticInnerClassSingleton.class
              LazyStaticInnerClassSingleton$LazyHolder.class
   優(yōu)點:寫法優(yōu)雅,利用了Java本身語法特點饺藤,性能高包斑,避免了內(nèi)存浪費,不能被反射破壞
   缺點:不優(yōu)雅
   create by yufeng on 2021/7/3 21:12
 */
public class LazyStaticInnerClassSingleton {

    private LazyStaticInnerClassSingleton(){
        if(LazyHolder.INSTANCE != null){
            throw new RuntimeException("不允許非法訪問");
        }
    }

    private static LazyStaticInnerClassSingleton getInstance(){
        return LazyHolder.INSTANCE;
    }

    private static class LazyHolder{
        private static final LazyStaticInnerClassSingleton INSTANCE = new LazyStaticInnerClassSingleton();
    }

}
4.序列化

序列化和反序列化后,單例模式會被破壞涕俗,因為反序列化重新開辟內(nèi)存重新創(chuàng)建對象罗丰,違背了單例的初衷

/**
 * create by yufeng on 2021/7/3 21:30
 */

public class SeriableSingleton implements Serializable {


    //序列化
    //把內(nèi)存中對象的狀態(tài)轉(zhuǎn)換為字節(jié)碼的形式
    //把字節(jié)碼通過IO輸出流,寫到磁盤上
    //永久保存下來咽袜,持久化

    //反序列化
    //將持久化的字節(jié)碼內(nèi)容丸卷,通過IO輸入流讀到內(nèi)存中來
    //轉(zhuǎn)化成一個Java對象
    public  final static SeriableSingleton INSTANCE = new SeriableSingleton();
    private SeriableSingleton(){}

    public static SeriableSingleton getInstance(){
        return INSTANCE;
    }

    private Object readResolve(){ return INSTANCE;}

}

通過jdk源碼分析我們可以看到readResolve()方法雖然解決了序列化破壞單例的問題,但是實際上是實例化了2次询刹,只不過新創(chuàng)建的對象沒有被返回而已谜嫉,如果該動作頻率加快內(nèi)存分配開銷也會加大。注冊式模式會解決該問題

5.注冊式單例模式

注冊式單例模式凹联,也叫登記式單例模式沐兰,每一個實例都會登記到某一個地方,使用唯一的標識獲取實例蔽挠,注冊式單例模式有2中:枚舉住闯、容器

5.1枚舉式單例模式

類似餓漢模式瓜浸,類加載的是就會實例化,也不會被序列化破壞比原,因為枚舉式用過類名和類對象找到唯一對象插佛,所以不能被加載多次,也不會通過反射破壞量窘,因為沒無參構(gòu)造雇寇,只有一個protected類型的構(gòu)造方法,在newInstance() 時有個強制判斷蚌铜,如果是枚舉那就直接拋出異常锨侯,跟靜態(tài)內(nèi)部類類似的處理。

/**
 * create by yufeng on 2021/7/3 22:30
 */
public enum EnumSingleton {
    INSTANCE;

    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static EnumSingleton getInstance(){return INSTANCE;}
}
5.2容器式單例模式

枚舉式單例跟餓漢模式差不多冬殃,都會加載的時候就進行了實例化囚痴,不適合大量創(chuàng)建單例對象的場景,所以就有了容器式單例模式

/**
 * create by yufeng on 2021/7/3 22:30
 */
public class ContainerSingleton {

    private ContainerSingleton(){}

    private static Map<String,Object> ioc = new ConcurrentHashMap<String, Object>();

    public static Object getInstance(String className){
        Object instance = null;
        if(!ioc.containsKey(className)){
            try {
                instance = Class.forName(className).newInstance();
                ioc.put(className, instance);
            }catch (Exception e){
                e.printStackTrace();
            }
            return instance;
        }else{
            return ioc.get(className);
        }
    }

}

容器式單例模式適用于需要大量創(chuàng)建單例模式對象的場景审葬,但是不是線程安全的

5.源碼地址

單例模式源碼地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末深滚,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子耳璧,更是在濱河造成了極大的恐慌成箫,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件旨枯,死亡現(xiàn)場離奇詭異蹬昌,居然都是意外死亡,警方通過查閱死者的電腦和手機攀隔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門皂贩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人昆汹,你說我怎么就攤上這事明刷。” “怎么了满粗?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵辈末,是天一觀的道長。 經(jīng)常有香客問我映皆,道長挤聘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任捅彻,我火速辦了婚禮组去,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘步淹。我一直安慰自己从隆,他們只是感情好诚撵,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著键闺,像睡著了一般寿烟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上艾杏,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天韧衣,我揣著相機與錄音,去河邊找鬼购桑。 笑死,一個胖子當著我的面吹牛氏淑,可吹牛的內(nèi)容都是我干的勃蜘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼假残,長吁一口氣:“原來是場噩夢啊……” “哼缭贡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起辉懒,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤阳惹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后眶俩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體莹汤,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年颠印,在試婚紗的時候發(fā)現(xiàn)自己被綠了纲岭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡线罕,死狀恐怖止潮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情钞楼,我是刑警寧澤喇闸,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站询件,受9級特大地震影響燃乍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜雳殊,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一橘沥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧夯秃,春花似錦座咆、人聲如沸痢艺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽堤舒。三九已至,卻和暖如春哺呜,著一層夾襖步出監(jiān)牢的瞬間舌缤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工某残, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留国撵,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓玻墅,卻偏偏與公主長得像介牙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子澳厢,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

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