七種Java單例模式詳解

博客同步

單例模式作為常用的設(shè)計(jì)模式之一糕再,無論是在各種第三方庫還是在我們?nèi)粘i_發(fā)中都非常常見霞扬,這里將介紹單例模式七種實(shí)現(xiàn)方式。

前提:jvm類加載

class 加載流程: 加載—–驗(yàn)證—–準(zhǔn)備—–解析—–初始化
在class文件中java編譯器會(huì)生成一個(gè)<clinit>()方法骤肛,在初始化階段jvm會(huì)調(diào)用它昌粤,該方法包含了對(duì)該類所有的靜態(tài)變量的賦值和靜態(tài)代碼塊執(zhí)行操作,并且 jvm保證了<clinit>()方法在多線程的執(zhí)行環(huán)境下安全缴挖,因此單例設(shè)計(jì)模式模式中我們使用靜態(tài)變量來存儲(chǔ)實(shí)例的引用。

一焚辅、單例模式之餓漢式

/**
 * 餓漢式
 */
public class SingletonDemo {

    //當(dāng)類加載初始化后映屋,就已經(jīng)完成了實(shí)例的創(chuàng)建
    private static SingletonDemo instance = new SingletonDemo();

    /**
     * 不讓外部 new
     */
    private SingletonDemo() {

    }

    public static SingletonDemo getInstance() {
        return instance;
    }

}

餓漢式分析

餓漢式的關(guān)鍵使用了靜態(tài)變量并且在類加載初始化后就完成了實(shí)例的創(chuàng)建,從而保證了多線程環(huán)境下實(shí)例的一致性同蜻,但是它不支持懶加載棚点,當(dāng)然如果過該類比較輕的話還是可以接受的。

二湾蔓、單例模式之懶漢式

/**
 * 懶漢式
 */
public class SingletonDemo {
    
    //僅僅定義靜態(tài)變量
    private static SingletonDemo instance = null;

    /**
     * 不讓外部 new
     */
    private SingletonDemo() {

    }

    public static SingletonDemo getInstance() {
        
        return instance!=null?instance:new SingletonDemo();
    }

}

懶漢式分析

懶漢式僅僅在在使用實(shí)例的時(shí)候才去創(chuàng)建實(shí)例的對(duì)象瘫析,在多線程環(huán)境下,實(shí)例可能會(huì)創(chuàng)建多次默责,線程不安全贬循,但是它支持懶加載。

三桃序、線程安全懶漢式

/**
 * 線程安全懶漢式
 */
public class SingletonDemo {

    //僅僅定義靜態(tài)變量
    private static SingletonDemo instance = null;

    /**
     * 不讓外部 new
     */
    private SingletonDemo() {

    }

    //使用synchronized 同步關(guān)鍵字杖虾,保證該方法多線程下只能單個(gè)線程使用
    public synchronized static SingletonDemo getInstance() {

        return instance!=null?instance:new SingletonDemo();
    }

}

線程安全懶漢式分析

通過synchronized 關(guān)鍵字修飾 getInstance方法實(shí)現(xiàn)線程安全,但是同一時(shí)刻只能有一個(gè)線程訪問媒熊,性能較低奇适。

四坟比、單例模式之雙重檢驗(yàn)

/**
 * 雙重檢驗(yàn)?zāi)J? */
public class SingletonDemo {

    //僅僅定義靜態(tài)變量
    private static SingletonDemo instance = null;

    /**
     * 不讓外部 new
     */
    private SingletonDemo() {

    }

    public static SingletonDemo getInstance() {
        
        if (instance==null){
            
            //同步代碼塊
            synchronized (SingletonDemo.class){
                if (instance == null) {
                    instance = new SingletonDemo();
                }
            }
            
        }
        return instance;
    }

}

雙重檢驗(yàn)分析

這種模式可能會(huì)引起空指針異常,new 一個(gè)對(duì)象需要經(jīng)歷:分配內(nèi)存空間-初始化-引用賦值(指向?qū)ο蟮牡刂罚┻^程,而且java中存在cpu指令重排序嚷往,因此在多線程環(huán)境下線程一執(zhí)行 可能執(zhí)行new對(duì)象:分配內(nèi)存空間-引用賦值-初始化葛账,當(dāng)執(zhí)行到引用賦值時(shí),線程二會(huì)看到instance!=null皮仁,但這時(shí)籍琳,對(duì)象并未完成初始化,對(duì)象是空的魂贬,直接使用會(huì)空指針異常巩割。因此這種方式也是線程不安全的。

volatile雙重檢驗(yàn)

/**
 * volatile雙重檢驗(yàn)?zāi)J? */
public class SingletonDemo {

    //僅僅定義靜態(tài)變量
    private volatile static SingletonDemo instance = null;

    /**
     * 不讓外部 new
     */
    private SingletonDemo() {

    }

    public static SingletonDemo getInstance() {

        if (instance==null){

            //同步代碼塊
            synchronized (SingletonDemo.class){
                if (instance == null) {
                    instance = new SingletonDemo();
                }
            }

        }
        return instance;
    }

}

volatile雙重檢驗(yàn)分析

volatile 在這的作用就是禁止指令重排序付燥,從而使對(duì)象的創(chuàng)建嚴(yán)格按照分配內(nèi)存空間-初始化-引用賦值(指向?qū)ο蟮牡刂罚┻^程宣谈,實(shí)現(xiàn)了線程安全。

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

/**
 * 靜態(tài)內(nèi)部類模式
 */
public class SingletonDemo {

    

    /**
     * 不讓外部 new
     */
    private SingletonDemo() {

    }
    

    public static SingletonDemo getInstance() {
        return Holder.instance;
    }
    
    //使用靜態(tài)內(nèi)部類來初始化instance
    private static class Holder{
        
        //當(dāng)類加載初始化后键科,就已經(jīng)完成了實(shí)例的創(chuàng)建
        private static SingletonDemo instance = new SingletonDemo();
        
    }

}

靜態(tài)內(nèi)部類模式分析

靜態(tài)內(nèi)部類模式歸根到底是<clinit>()同步方法帶來的結(jié)果闻丑,這種模式實(shí)現(xiàn)了線程安全和懶加載,被公認(rèn)為最好的單例模式之一勋颖。

枚舉模式

/**
 * 枚舉模式
 */
public class SingletonDemo {



    /**
     * 不讓外部 new
     */
    private SingletonDemo() {

    }


    public static SingletonDemo getInstance() {
        return Holder.INSTANCE.instance;
    }

    //使用枚舉
    private  enum  Holder{

        INSTANCE;
        private SingletonDemo instance;
        
        Holder(){
            instance = new SingletonDemo();
        }

    }

}

枚舉模式分析

主要利用了enum的特性嗦嗡,保證線程安全。

總結(jié)

各種模式各有有缺點(diǎn)饭玲,但是對(duì)懶加載和高性能有要求的侥祭,還是用靜態(tài)內(nèi)部類類模式、volatile雙重檢驗(yàn)?zāi)J角牙濉⒚杜e模式矮冬,既能滿足線程安全,還能滿足性能要求次哈。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末胎署,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子窑滞,更是在濱河造成了極大的恐慌琼牧,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哀卫,死亡現(xiàn)場(chǎng)離奇詭異巨坊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)聊训,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門抱究,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人带斑,你說我怎么就攤上這事鼓寺⊙猓” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵妈候,是天一觀的道長(zhǎng)敢靡。 經(jīng)常有香客問我,道長(zhǎng)苦银,這世上最難降的妖魔是什么啸胧? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮幔虏,結(jié)果婚禮上纺念,老公的妹妹穿的比我還像新娘。我一直安慰自己想括,他們只是感情好陷谱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著瑟蜈,像睡著了一般烟逊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上铺根,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天宪躯,我揣著相機(jī)與錄音,去河邊找鬼位迂。 笑死访雪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掂林。 我是一名探鬼主播冬阳,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼党饮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起驳庭,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤刑顺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后饲常,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蹲堂,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年贝淤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了柒竞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡播聪,死狀恐怖朽基,靈堂內(nèi)的尸體忽然破棺而出布隔,到底是詐尸還是另有隱情,我是刑警寧澤稼虎,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布衅檀,位于F島的核電站,受9級(jí)特大地震影響霎俩,放射性物質(zhì)發(fā)生泄漏哀军。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一打却、第九天 我趴在偏房一處隱蔽的房頂上張望杉适。 院中可真熱鬧,春花似錦柳击、人聲如沸猿推。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽彤守。三九已至,卻和暖如春哭靖,著一層夾襖步出監(jiān)牢的瞬間具垫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工试幽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留筝蚕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓铺坞,卻偏偏與公主長(zhǎng)得像起宽,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子济榨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

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