java設(shè)計模式-單例模式及其幾種實現(xiàn)方式

1.定義

確保一個類只有一個實例露筒,并提供一個全局訪問點达箍。

2.實現(xiàn)方式

2.1 聲明即創(chuàng)建對象方式

package com.methon.singleton;

public class SigDemo01 {
    private static SigDemo01 INSTANCE=new SigDemo01 ();
    private SigDemo01 (){};
    public static SigDemo01 getInstance(){
        return INSTANCE;
    }
    public static void main(String[] args) {
        SigDemo01 sig01=SigDemo01 .getInstance();
        SigDemo01 sig02=SigDemo01 .getInstance();
        /* 判斷是否是同一個對象 */
        System.out.println(sig01==sig02);
    }
}

其中static聲明的靜態(tài)成員INSTANCE只會在類加載的時候創(chuàng)建一次,new一個對象骚烧。
私有的構(gòu)造函數(shù)保證只能在此類中調(diào)用,其他類中想要獲取實例只能調(diào)用getInstance()方法。
返回static對象刻两。保證對象的唯一性赖草。上面的代碼也可以寫成:

package com.methon.singleton;

public class SigDemo02{
    private static SigDemo02 INSTANCE;
    static {
        INSTANCE=new SigDemo02();
    }
    private SigDemo02(){};
    public static  SigDemo02 getInstance(){
        return INSTANCE;
    }
    public static void main(String[] args) {
        SigDemo02 sig01=SigDemo02.getInstance();
        SigDemo02 sig02=SigDemo02.getInstance();
        /* 判斷是否是同一個對象 */
        System.out.println(sig01==sig02);
    }

}

2.2 懶加載方式

以下為懶加載方式的演變,方法逐漸變得趨于完美

2.2.1 錯誤的懶加載寫法(不支持多線程)

package com.methon.singleton;

public class SigDemo03{
    private static SigDemo03 INSTANCE;
    private SigDemo03(){
    }
    public static SigDemo03 getInstance(){
        if(INSTANCE==null){
            INSTANCE=new SigDemo03();
        }
        return INSTANCE;
    }
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(()-> System.out.println(SigDemo03.getInstance().hashCode())).start();
        }
    }

}

如果代碼中沒有多線程,則程序沒有任何問題。但存在多線程的情況下,執(zhí)行到if(INSTANCE==null)后乡翅, INSTANCE=new SigDemo03()語句前鳞疲,可能有多個線程通過了if(INSTANCE==null)的判斷,從而不能保證創(chuàng)建出的對象有且僅有1個蠕蚜。

2.2.2 懶加載的正確寫法(加鎖)

package com.methon.singleton;

public class SigDemo04{

    private static SigDemo04 INSTANCE;

    private SigDemo04() {
    }

    public static synchronized SigDemo04 getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new SigDemo04();
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> System.out.println(SigDemo04.getInstance().hashCode())).start();
        }
    }
}

對比之前的方法尚洽,只是在getInstance()方法上添加了synchronized ,保證了線程安全靶累。但這樣做的話降低了程序的執(zhí)行效率腺毫。

2.2.3 為了解決加鎖后程序效率變低而采取的錯誤處理

package com.methon.singleton;

public class SigDemo05{

    private static SigDemo05 INSTANCE;

    private SigDemo05() {
    }

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

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> System.out.println(SigDemo05 .getInstance().hashCode())).start();
        }
    }
}


為了提高效率,在判斷INSTANCE == null之后在進行加鎖的判斷。但是請注意挣柬,雖然進行了加鎖操作拴曲,但是最后線程們都會創(chuàng)建新的對象。

2.2.4 為了解決加鎖后程序效率變低而采取的正確處理

package com.methon.singleton;

public class SigDemo06{

    private static SigDemo06 INSTANCE;

    private SigDemo06 () {
    }

    public static SigDemo06 getInstance() {
        if (INSTANCE == null) {
            synchronized (SigDemo06 .class) {
                if (INSTANCE == null) {
                    INSTANCE = new SigDemo06 ();
                }

            }
        }
        return INSTANCE;
    }

    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> System.out.println(SigDemo06 .getInstance().hashCode())).start();
        }
    }
}


此方式雖然有些繁瑣凛忿,但是正確的做法澈灼。在判斷INSTANCE == null后進行加鎖,之后在進行判空操作。仍為空后在進行new新的對象叁熔。避免了只要為空就會創(chuàng)建新的對象委乌。

2.2.5 較完美的靜態(tài)內(nèi)部類方式

package com.methon.singleton;
public class SigDemo07{
    private SigDemo07() {

    }
    public static SigDemo07 getInstance() {
        return SigDemo07Holder.INSTANCE;
    }
    private static class SigDemo07Holder {
        private final static SigDemo07 INSTANCE = new SigDemo07();
    }
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> System.out.println(SigDemo07.getInstance().hashCode())).start();
        }
    }
}

此種方式,避免了聲明即創(chuàng)建對象的方式荣回,采用靜態(tài)內(nèi)部類的方式遭贸,需要時才創(chuàng)建對象。比較完美且代碼不冗余心软。

2.2.6 effictive java給出的方式

package com.methon.singleton;
public enum  SigDemo08{
    INSTANCE;
    public static void main(String[] args) {
        for (int i = 0; i < 100; i++) {
            new Thread(() -> System.out.println(SigDemo08.INSTANCE.hashCode())).start();
        }
    }
}

直接設(shè)置成了枚舉類型壕吹,且僅有一個枚舉量INSTANCE。

3.總結(jié)

正常需要單例模式的情況一般都需要創(chuàng)建對象删铃。所以是否進行懶加載區(qū)別相差不大耳贬。故方法2.1滿足平常使用的要求。除此之外猎唁,方法2.2.4, 2.2.5, 2.2.6更為完美咒劲,推薦使用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诫隅,一起剝皮案震驚了整個濱河市腐魂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逐纬,老刑警劉巖蛔屹,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異豁生,居然都是意外死亡兔毒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門沛硅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來眼刃,“玉大人绕辖,你說我怎么就攤上這事摇肌。” “怎么了仪际?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵围小,是天一觀的道長。 經(jīng)常有香客問我树碱,道長肯适,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任成榜,我火速辦了婚禮框舔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己刘绣,他們只是感情好樱溉,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纬凤,像睡著了一般福贞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上停士,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天挖帘,我揣著相機與錄音,去河邊找鬼恋技。 笑死拇舀,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的猖任。 我是一名探鬼主播你稚,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼朱躺!你這毒婦竟也來了刁赖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤长搀,失蹤者是張志新(化名)和其女友劉穎宇弛,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體源请,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡枪芒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了谁尸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舅踪。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖良蛮,靈堂內(nèi)的尸體忽然破棺而出抽碌,到底是詐尸還是另有隱情,我是刑警寧澤决瞳,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布货徙,位于F島的核電站,受9級特大地震影響皮胡,放射性物質(zhì)發(fā)生泄漏痴颊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一屡贺、第九天 我趴在偏房一處隱蔽的房頂上張望蠢棱。 院中可真熱鬧锌杀,春花似錦、人聲如沸泻仙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饰豺。三九已至亿鲜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冤吨,已是汗流浹背蒿柳。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留漩蟆,地道東北人垒探。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像怠李,于是被迫代替她去往敵國和親圾叼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350