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

1 懶漢模式

此種最簡(jiǎn)單、方便,缺點(diǎn)可以忽略,<font color = 'red'>建議使用</font>

package com.xin.demo.sigle;

/**
 * 懶漢模式,簡(jiǎn)單實(shí)用,推薦使用這種寫(xiě)法
 * 類(lèi)加載到內(nèi)存后就實(shí)例化一個(gè)對(duì)象,jvm保證線程的安全
 * 缺點(diǎn):不管是否使用,類(lèi)加載時(shí)就進(jìn)行實(shí)例化操作
 */
public class Single01 {

    /**
     * 類(lèi)加載時(shí)進(jìn)行對(duì)象的創(chuàng)建,jvm 保證類(lèi)線程安全
     */
    private static final Single01 INSTANCE = new Single01();

    /**
     * 構(gòu)造器必須私有化,不允許外部進(jìn)行對(duì)象的創(chuàng)建
     */
    private Single01() {
    }

    public static Single01 getINSTANCE() {
        return INSTANCE;
    }

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

2 同1 靜態(tài)代碼塊的寫(xiě)法

package com.xin.demo.sigle;

/**
 * 同01
 */
public class Single02 {

    /**
     * 類(lèi)加載時(shí)進(jìn)行對(duì)象的創(chuàng)建,jvm 保證類(lèi)線程安全
     */
    private static final Single02 INSTANCE;

    // 同01 只是改成了 靜態(tài)代碼塊
    static {
        INSTANCE = new Single02();
    }

    /**
     * 構(gòu)造器必須私有化,不允許外部進(jìn)行對(duì)象的創(chuàng)建
     */
    private Single02() {
    }

    public static Single02 getINSTANCE() {
        return INSTANCE;
    }

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

3 餓漢模式(非線程安全)

按需分配,此方法存在線程安全問(wèn)題

package com.xin.demo.sigle;

/**
 * 餓漢模式,按需分配
 */
public class Single03 {

    private static Single03 INSTANCE = null;

    /**
     * 構(gòu)造器必須私有化,不允許外部進(jìn)行對(duì)象的創(chuàng)建
     */
    private Single03() {
    }

    public static Single03 getINSTANCE() {
        if (INSTANCE == null) {
            // 此處驗(yàn)證多線程并發(fā)的問(wèn)題,雖然此處達(dá)到了 按需分配,但是多線程時(shí)不安全
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE = new Single03();
        }
        return INSTANCE;
    }

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

4 餓漢模式(線程安全)

此處采用給方法上加 synchronized 關(guān)鍵字解決了線程安全問(wèn)題,同時(shí)帶來(lái)了性能降低的問(wèn)題,每次獲取實(shí)例時(shí)都會(huì)進(jìn)行等待。

package com.xin.demo.sigle;

/**
 * 餓漢模式,按需分配
 */
public class Single04 {

    private static Single04 INSTANCE = null;

    /**
     * 構(gòu)造器必須私有化,不允許外部進(jìn)行對(duì)象的創(chuàng)建
     */
    private Single04() {
    }

    public static synchronized Single04 getINSTANCE() {
        // 加鎖 保證線程安全,但是這種方式帶來(lái)了 效率下降的問(wèn)題
        if (INSTANCE == null) {
            // 此處驗(yàn)證多線程并發(fā)的問(wèn)題,雖然此處達(dá)到了 按需分配,但是多線程時(shí)不安全
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            INSTANCE = new Single04();
        }
        return INSTANCE;
    }

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

5 餓漢模式(解決性能問(wèn)題)

此種存在問(wèn)題,通過(guò)代碼塊未達(dá)到目的,時(shí)6 的過(guò)渡。

package com.xin.demo.sigle;

/**
 * 餓漢模式,按需分配
 */
public class Single05 {

    private static Single05 INSTANCE = null;

    /**
     * 構(gòu)造器必須私有化,不允許外部進(jìn)行對(duì)象的創(chuàng)建
     */
    private Single05() {
    }

    public static Single05 getINSTANCE() {

        if (INSTANCE == null) {
            // 此處驗(yàn)證多線程并發(fā)的問(wèn)題,雖然此處達(dá)到了 按需分配,但是多線程時(shí)不安全
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 為了提高效率 通過(guò)用代碼塊的方式進(jìn)行解決,如果為null 則加鎖,此方法 依然不可行,未解決多線程的問(wèn)題
            synchronized (Single05.class) {
                // 多線程時(shí) 第一處多個(gè)為null,有多個(gè)線程進(jìn)了此鎖,依然會(huì)產(chǎn)生多個(gè)對(duì)象
                INSTANCE = new Single05();
            }
        }
        return INSTANCE;
    }

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

6 餓漢模式(完美的餓漢模式)

package com.xin.demo.sigle;

/**
 * 餓漢模式,按需分配
 */
public class Single06 {

    private static Single06 INSTANCE = null;

    /**
     * 構(gòu)造器必須私有化,不允許外部進(jìn)行對(duì)象的創(chuàng)建
     */
    private Single06() {
    }

    public static Single06 getINSTANCE() {

        // 為了提高效率,如果為null 則不進(jìn)鎖
        if (INSTANCE == null) {
            // 此處驗(yàn)證多線程并發(fā)的問(wèn)題,雖然此處達(dá)到了 按需分配,但是多線程時(shí)不安全
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 為了提高效率 通過(guò)用代碼塊的方式進(jìn)行解決,如果為null 則加鎖,此方法 依然不可行,未解決多線程的問(wèn)題
            synchronized (Single06.class) {
                // 多線程時(shí) 第一處多個(gè)為null,有多個(gè)線程進(jìn)了此鎖,依然會(huì)產(chǎn)生多個(gè)對(duì)象
                // 因此 此處需要在進(jìn)行一次判斷,雙重判斷
                if (INSTANCE == null) {
                    INSTANCE = new Single06();
                }
            }
        }
        return INSTANCE;
    }

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

7 通過(guò)內(nèi)部類(lèi)實(shí)現(xiàn)

package com.xin.demo.sigle;

/**
 * 通過(guò)內(nèi)部類(lèi) 來(lái)實(shí)現(xiàn)加載外部類(lèi)時(shí)不會(huì)加載內(nèi)部類(lèi),這樣可以實(shí)現(xiàn)懶加載
 */
public class Single07 {


    // 內(nèi)部類(lèi)不會(huì)在類(lèi)加載的時(shí)候加載,只有在調(diào)用的時(shí)候進(jìn)行加載,因此是按需分配,jvm保證了線程的安全
    public static class SingleHolder {
        protected static Single07 INSTANCE = new Single07();
    }

    /**
     * 構(gòu)造器必須私有化,不允許外部進(jìn)行對(duì)象的創(chuàng)建
     */
    private Single07() {
    }

    public static Single07 getINSTANCE() {
        return SingleHolder.INSTANCE;
    }

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

8 通過(guò)枚舉實(shí)現(xiàn)

effective java 中建議采用 枚舉來(lái)實(shí)習(xí)單例 ,<font color='red'>推薦使用</font>

package com.xin.demo.sigle;

/**
 * 通過(guò) 枚舉保證了線程的安全,也可以防止反序列化
 */
public enum Single08 {
    INSTANCE;

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

9 通過(guò)枚舉實(shí)現(xiàn)

枚舉可以實(shí)現(xiàn)接口,無(wú)法進(jìn)行繼承,大多數(shù)情況下還是需要用到類(lèi)的,因此我們通過(guò)在類(lèi)中嵌套枚舉以達(dá)到單列。

package com.xin.demo.sigle;

/**
 * 通過(guò) 枚舉保證了線程的安全,也可以防止反序列化
 *
 * 枚舉沒(méi)法進(jìn)行 繼承,因此有時(shí)候通常需要類(lèi)來(lái)進(jìn)行操作,此處是將類(lèi) 通過(guò)枚舉來(lái)實(shí)現(xiàn)單列
 */
public class Single09 {


    public static Single09 getINSTANCE() {
        return Single09Enum.SINGLE09.getInstance();
    }

    public enum Single09Enum {
        SINGLE09;
        private final Single09 INSTANCE;

        Single09Enum() {
            INSTANCE = new Single09();
        }

        public Single09 getInstance() {
            return INSTANCE;
        }
    }

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

https://gitee.com/0x208_jackson/design-patterns

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

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

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