设计模式——单例模式

1 懒汉模式

此种最简单、方便,缺点可以忽略,<font color = 'red'>建议使用</font>

package com.xin.demo.sigle;

/**
 * 懒汉模式,简单实用,推荐使用这种写法
 * 类加载到内存后就实例化一个对象,jvm保证线程的安全
 * 缺点:不管是否使用,类加载时就进行实例化操作
 */
public class Single01 {

    /**
     * 类加载时进行对象的创建,jvm 保证类线程安全
     */
    private static final Single01 INSTANCE = new Single01();

    /**
     * 构造器必须私有化,不允许外部进行对象的创建
     */
    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 静态代码块的写法

package com.xin.demo.sigle;

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

    /**
     * 类加载时进行对象的创建,jvm 保证类线程安全
     */
    private static final Single02 INSTANCE;

    // 同01 只是改成了 静态代码块
    static {
        INSTANCE = new Single02();
    }

    /**
     * 构造器必须私有化,不允许外部进行对象的创建
     */
    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 饿汉模式(非线程安全)

按需分配,此方法存在线程安全问题

package com.xin.demo.sigle;

/**
 * 饿汉模式,按需分配
 */
public class Single03 {

    private static Single03 INSTANCE = null;

    /**
     * 构造器必须私有化,不允许外部进行对象的创建
     */
    private Single03() {
    }

    public static Single03 getINSTANCE() {
        if (INSTANCE == null) {
            // 此处验证多线程并发的问题,虽然此处达到了 按需分配,但是多线程时不安全
            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 关键字解决了线程安全问题,同时带来了性能降低的问题,每次获取实例时都会进行等待。

package com.xin.demo.sigle;

/**
 * 饿汉模式,按需分配
 */
public class Single04 {

    private static Single04 INSTANCE = null;

    /**
     * 构造器必须私有化,不允许外部进行对象的创建
     */
    private Single04() {
    }

    public static synchronized Single04 getINSTANCE() {
        // 加锁 保证线程安全,但是这种方式带来了 效率下降的问题
        if (INSTANCE == null) {
            // 此处验证多线程并发的问题,虽然此处达到了 按需分配,但是多线程时不安全
            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 饿汉模式(解决性能问题)

此种存在问题,通过代码块未达到目的,时6 的过渡。

package com.xin.demo.sigle;

/**
 * 饿汉模式,按需分配
 */
public class Single05 {

    private static Single05 INSTANCE = null;

    /**
     * 构造器必须私有化,不允许外部进行对象的创建
     */
    private Single05() {
    }

    public static Single05 getINSTANCE() {

        if (INSTANCE == null) {
            // 此处验证多线程并发的问题,虽然此处达到了 按需分配,但是多线程时不安全
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 为了提高效率 通过用代码块的方式进行解决,如果为null 则加锁,此方法 依然不可行,未解决多线程的问题
            synchronized (Single05.class) {
                // 多线程时 第一处多个为null,有多个线程进了此锁,依然会产生多个对象
                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;

    /**
     * 构造器必须私有化,不允许外部进行对象的创建
     */
    private Single06() {
    }

    public static Single06 getINSTANCE() {

        // 为了提高效率,如果为null 则不进锁
        if (INSTANCE == null) {
            // 此处验证多线程并发的问题,虽然此处达到了 按需分配,但是多线程时不安全
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 为了提高效率 通过用代码块的方式进行解决,如果为null 则加锁,此方法 依然不可行,未解决多线程的问题
            synchronized (Single06.class) {
                // 多线程时 第一处多个为null,有多个线程进了此锁,依然会产生多个对象
                // 因此 此处需要在进行一次判断,双重判断
                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 通过内部类实现

package com.xin.demo.sigle;

/**
 * 通过内部类 来实现加载外部类时不会加载内部类,这样可以实现懒加载
 */
public class Single07 {


    // 内部类不会在类加载的时候加载,只有在调用的时候进行加载,因此是按需分配,jvm保证了线程的安全
    public static class SingleHolder {
        protected static Single07 INSTANCE = new Single07();
    }

    /**
     * 构造器必须私有化,不允许外部进行对象的创建
     */
    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 通过枚举实现

effective java 中建议采用 枚举来实习单例 ,<font color='red'>推荐使用</font>

package com.xin.demo.sigle;

/**
 * 通过 枚举保证了线程的安全,也可以防止反序列化
 */
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 通过枚举实现

枚举可以实现接口,无法进行继承,大多数情况下还是需要用到类的,因此我们通过在类中嵌套枚举以达到单列。

package com.xin.demo.sigle;

/**
 * 通过 枚举保证了线程的安全,也可以防止反序列化
 *
 * 枚举没法进行 继承,因此有时候通常需要类来进行操作,此处是将类 通过枚举来实现单列
 */
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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容