Java單例模式

餓漢模式:

/**
 * 單例-餓漢模式(即靜態(tài)創(chuàng)建)
 * 優(yōu)點:線程安全,實現(xiàn)簡單
 * 缺點:SingleInstance 在類加載的時候就實例化了,即便不用。(如果不用的話會造成內(nèi)存浪費)
 * @author Rambo(浩祥)
 * @create 2017-09-21
 **/
public final class SingleInstance1 {
    private static SingleInstance1 singleInstance = new SingleInstance1();

    private SingleInstance1(){}

    public static SingleInstance1 getSingleInstance(){
        return singleInstance;
    }
}

懶漢模式1

/**
 * 單例--懶漢模式1(即用到的時候再去創(chuàng)建)
 * 優(yōu)點:不用場景下,比懶漢模式節(jié)省內(nèi)存
 * 缺點:非線程安全,耗時比懶漢模式長
 * @author Rambo(浩祥)
 * @create 2017-08-25
 **/
public final class SingleInstance2 {

    private static SingleInstance2 singleInstance = null;

    private SingleInstance2(){

    }

    public static SingleInstance2 getSingleInstance(){
        try {
            if (singleInstance == null){
                // 休眠50ms構(gòu)造線程非安全的場景
                Thread.sleep(50);
                singleInstance = new SingleInstance2();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return singleInstance;
    }
}

懶漢模式2

/**
 * 單例-懶漢模式2
 * 優(yōu)點:較懶漢模式1比線程安全
 * 缺點:較懶漢模式1耗時,因為要進行線程同步
 * @author Rambo(浩祥)
 * @create 2017-09-21
 **/
public class SingleInstance3 {
    private static SingleInstance3 singleInstance = null;

    private SingleInstance3(){

    }

    public static synchronized SingleInstance3 getSingleInstance(){
        try {
            if (singleInstance == null){
                // 休眠50ms構(gòu)造線程非安全的場景
                Thread.sleep(50);
                singleInstance = new SingleInstance3();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return singleInstance;
    }
}

懶漢模式3

/**
 * 單例-懶漢模式3
 * 優(yōu)點-線程安全,比懶漢模式2節(jié)約用時
 * @author Rambo(浩祥)
 * @create 2017-09-21
 **/
public class SingleInstance4 {
    private static SingleInstance4 singleInstance = null;

    private SingleInstance4(){

    }

    public static SingleInstance4 getSingleInstance(){
        try {
            if (singleInstance == null){
                // 休眠50ms構(gòu)造線程非安全的場景
                Thread.sleep(50);
                synchronized (SingleInstance4.class){
                    if (singleInstance == null){
                        singleInstance = new SingleInstance4();
                    }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return singleInstance;
    }
}

懶漢模式4

/**
 * 單例-懶漢模式4
 *
 * @author Rambo(浩祥)
 * @create 2017-09-21
 **/
public class SingleInstance5 {
    private static class GetInstance{
        private static SingleInstance5 singleInstance = new SingleInstance5();
    }
    private SingleInstance5(){

    }
    // 只有調(diào)用到該方法是GetInstance才會加載,singleInstance才會初始化
    public static SingleInstance5 getSingleInstance(){
        return GetInstance.singleInstance;
    }
}

測試程序

驗證不同單例模式的實例獲取時間僻弹、內(nèi)存占用芽淡、線程安全等

import com.rambo.memory.MemoryCounter;

/**
 * @author Rambo(浩祥)
 * @create 2017-03-09
 **/
public class Practice {
    // MemoryCounter是自己寫的對象內(nèi)存的計算類
    private static MemoryCounter memoryCounter = new MemoryCounter();

    public static void main(String[] args) {

        Thread getInstanceThread = new Thread(new Runnable() {
            @Override
            public void run() {
                getInstance();
            }
        });
        getInstanceThread.start();

        Thread getInstanceThread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                getInstance();
            }
        });
        getInstanceThread2.start();
    }

    private static void getInstance() {
        long startTime = System.currentTimeMillis();
//        SingleInstance1 singleInstance1 = SingleInstance1.getSingleInstance();
//        System.out.println(Thread.currentThread().getName() + ":singleInstance1獲取對象消耗用時:" + (System.currentTimeMillis() - startTime));
//        System.out.println(Thread.currentThread().getName() + ":singleInstance1對象hashCode:" + Integer.toString(singleInstance1.hashCode()));
//        System.out.println(Thread.currentThread().getName() + ":singleInstance1線程對象大小:" + memoryCounter.estimate(singleInstance1));

//        SingleInstance2 singleInstance2 = SingleInstance2.getSingleInstance();
//        System.out.println(Thread.currentThread().getName() + ":singleInstance2獲取對象消耗用時:" + (System.currentTimeMillis() - startTime));
//        System.out.println(Thread.currentThread().getName() + ":singleInstance2對象hashCode:" + Integer.toString(singleInstance2.hashCode()));
//        System.out.println(Thread.currentThread().getName() + ":singleInstance2線程對象大小:" + memoryCounter.estimate(singleInstance2));
//
//        SingleInstance3 singleInstance3 = SingleInstance3.getSingleInstance();
//        System.out.println(Thread.currentThread().getName() + ":singleInstance3獲取對象消耗用時:" + (System.currentTimeMillis() - startTime));
//        System.out.println(Thread.currentThread().getName() + ":singleInstance3對象hashCode:" + Integer.toString(singleInstance3.hashCode()));
//        System.out.println(Thread.currentThread().getName() + ":singleInstance3線程對象大小:" + memoryCounter.estimate(singleInstance3));
//
//        SingleInstance4 singleInstance4 = SingleInstance4.getSingleInstance();
//        System.out.println(Thread.currentThread().getName() + ":singleInstance4獲取對象消耗用時:" + (System.currentTimeMillis() - startTime));
//        System.out.println(Thread.currentThread().getName() + ":singleInstance4對象hashCode:" + Integer.toString(singleInstance4.hashCode()));
//        System.out.println(Thread.currentThread().getName() + ":singleInstance4線程對象大小:" + memoryCounter.estimate(singleInstance4));
//
        SingleInstance5 singleInstance5 = SingleInstance5.getSingleInstance();
        System.out.println(Thread.currentThread().getName() + ":singleInstance5獲取對象消耗用時:" + (System.currentTimeMillis() - startTime));
        System.out.println(Thread.currentThread().getName() + ":singleInstance5對象hashCode:" + Integer.toString(singleInstance5.hashCode()));
        System.out.println(Thread.currentThread().getName() + ":singleInstance5線程對象大小:" + memoryCounter.estimate(singleInstance5));
    }
}

運行結(jié)果如下:

餓漢
懶漢1绿淋,非線程安全
懶漢2
懶漢3
懶漢4

注:耗時大于50的是因為加了sleep(50)模擬線程非安全
注:實際應(yīng)用建議應(yīng)用懶漢4的方式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谤饭,一起剝皮案震驚了整個濱河市璃饱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌苍柏,老刑警劉巖尼斧,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姜贡,死亡現(xiàn)場離奇詭異试吁,居然都是意外死亡,警方通過查閱死者的電腦和手機楼咳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門熄捍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人母怜,你說我怎么就攤上這事余耽。” “怎么了苹熏?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵碟贾,是天一觀的道長。 經(jīng)常有香客問我轨域,道長袱耽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任干发,我火速辦了婚禮朱巨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘枉长。我一直安慰自己冀续,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布必峰。 她就那樣靜靜地躺著洪唐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吼蚁。 梳的紋絲不亂的頭發(fā)上桐罕,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音桂敛,去河邊找鬼功炮。 笑死,一個胖子當(dāng)著我的面吹牛术唬,可吹牛的內(nèi)容都是我干的薪伏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼粗仓,長吁一口氣:“原來是場噩夢啊……” “哼嫁怀!你這毒婦竟也來了设捐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤塘淑,失蹤者是張志新(化名)和其女友劉穎萝招,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體存捺,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡槐沼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捌治。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片岗钩。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖肖油,靈堂內(nèi)的尸體忽然破棺而出兼吓,到底是詐尸還是另有隱情,我是刑警寧澤森枪,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布视搏,位于F島的核電站,受9級特大地震影響县袱,放射性物質(zhì)發(fā)生泄漏浑娜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一显拳、第九天 我趴在偏房一處隱蔽的房頂上張望棚愤。 院中可真熱鬧,春花似錦杂数、人聲如沸宛畦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽次和。三九已至,卻和暖如春那伐,著一層夾襖步出監(jiān)牢的瞬間踏施,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工罕邀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留畅形,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓诉探,卻偏偏與公主長得像日熬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子肾胯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,527評論 2 349

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

  • 目錄一.什么是單例竖席?二.有幾種耘纱?三.應(yīng)用場景四.注意的地方 一.什么是單例? 單例模式 保證一個類在內(nèi)存中只有一個...
    在挖坑的猿閱讀 848評論 0 0
  • 概述 Java中單例模式是一種常見的設(shè)計模式毕荐,單例模式總共有7種寫法束析。 懶漢,線程不安全 懶漢憎亚,線程安全 餓漢 餓...
    HikariCP閱讀 320評論 0 2
  • 一员寇、前言 作為對象的創(chuàng)建模式,單例模式確保某一個類只有一個實例虽填,而且自行實例化并向整個系統(tǒng)提供這個實例丁恭。這個類稱為...
    manimaniho閱讀 437評論 0 0
  • 對于明知不可能卻還糾結(jié)的行為曹动,值得你反思斋日。你要的是一種感覺而不是一個人。這種感覺誰給你墓陈,你就覺得那就是恶守。呵呵……你...
    Ada心依閱讀 182評論 1 1