美文网首页
单例模式

单例模式

作者: zzj0990 | 来源:发表于2020-12-28 00:00 被阅读0次

    你真的了解单例模式么?
    废话不多说,直接上干货

    饿汉式

    /**
     * 饿汉式
     * 类加载到内存后,就实例化一个单例,JVM保证线程安全
     * 简单实用,推荐使用!
     * 唯一缺点:不管用到与否,类装载时就完成实例化
     * (话说你不用的,你装载它干啥)
     */
    public class Mgr01 {
        private static final Mgr01 INSTANCE = new Mgr01();
        private Mgr01() {}
        public static Mgr01 getInstance() {
            return INSTANCE;
        }
        public void m() {
            System.out.println("m");
        }
        public static void main(String[] args) {
            Mgr01 m1 = Mgr01.getInstance();
            Mgr01 m2 = Mgr01.getInstance();
            System.out.println(m1 == m2);
        }
    }
    /**
     * 跟Mgr01是一个意思
     */
    public class Mgr02 {
        private static final Mgr02 INSTANCE;
        static {
            INSTANCE = new Mgr02();
        }
        private Mgr02() {}
        public static Mgr02 getInstance() {
            return INSTANCE;
        }
        public void m() {
            System.out.println("m");
        }
        public static void main(String[] args) {
            Mgr02 m1 = Mgr02.getInstance();
            Mgr02 m2 = Mgr02.getInstance();
            System.out.println(m1 == m2);
        }
    }
    

    懒汉式

    /**
     * lazy loading
     * 也称懒汉式
     * 虽然达到了按需初始化的目的,但却带来线程不安全的问题
     * 达不到单利的目的
     */
    public class Mgr03 {
        private static Mgr03 INSTANCE;
        private Mgr03() {}
        public static Mgr03 getInstance() {
            if (INSTANCE == null) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                INSTANCE = new Mgr03();
            }
            return INSTANCE;
        }
        public void m() {
            System.out.println("m");
        }
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(() ->
                        System.out.println(Mgr03.getInstance().hashCode())
                ).start();
            }
        }
    }
    /**
     * lazy loading
     * 也称懒汉式
     * 虽然达到了按需初始化的目的,但却带来线程不安全的问题
     * 可以通过synchronized解决,但也带来效率下降
     * 注意:synchronized 不能禁止指令重排序
     */
    public class Mgr04 {
        private static Mgr04 INSTANCE;
        private Mgr04() {}
        public static synchronized Mgr04 getInstance() {
            if (INSTANCE == null) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                INSTANCE = new Mgr04();
            }
            return INSTANCE;
        }
        public void m() {
            System.out.println("m");
        }
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(() -> {
                    System.out.println(Mgr04.getInstance().hashCode());
                }).start();
            }
        }
    }
    /**
     * lazy loading
     * 也称懒汉式
     * 虽然达到了按需初始化的目的,但却带来线程不安全的问题
     * 可以通过synchronized解决,但也带来效率下降
     * 同Mgr03一样达不到单利目的
     */
    public class Mgr05 {
        private static Mgr05 INSTANCE;
        private Mgr05() {}
        public static Mgr05 getInstance() {
            if (INSTANCE == null) {
                //妄图通过减小同步代码块的方式提高效率,然后不可行
                synchronized (Mgr05.class) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    INSTANCE = new Mgr05();
                }
            }
            return INSTANCE;
        }
        public void m() {
            System.out.println("m");
        }
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(() -> {
                    System.out.println(Mgr05.getInstance().hashCode());
                }).start();
            }
        }
    }
    /**
     * lazy loading
     * 也称懒汉式
     * 虽然达到了按需初始化的目的,但却带来线程不安全的问题
     * 可以通过synchronized解决,但也带来效率下降
     * 注意:volatile - 是禁止指令重排序的(从INSTANCE = new Mgr06() 分为3部 说起)。
     */
    public class Mgr06 {
        private static volatile Mgr06 INSTANCE; //JIT
        private Mgr06() {}
        public static Mgr06 getInstance() {
            if (INSTANCE == null) {
                // 双重检查
                synchronized (Mgr06.class) {
                    if (INSTANCE == null) {
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        INSTANCE = new Mgr06();
                    }
                }
            }
            return INSTANCE;
        }
        public void m() {
            System.out.println("m");
        }
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(() -> {
                    System.out.println(Mgr06.getInstance().hashCode());
                }).start();
            }
        }
    }
    

    对象创建过程-指令重排:https://www.jianshu.com/p/97d20f8c5305

    静态内部类方式

    /**
     * 静态内部类方式
     * JVM保证单例
     * 加载外部类时不会加载内部类,这样可以实现懒加载
     */
    public class Mgr07 {
        private Mgr07() {
        }
        private static class Mgr07Holder {
            private final static Mgr07 INSTANCE = new Mgr07();
        }
        public static Mgr07 getInstance() {
            return Mgr07Holder.INSTANCE;
        }
        public void m() {
            System.out.println("m");
        }
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(() -> {
                    System.out.println(Mgr07.getInstance().hashCode());
                }).start();
            }
        }
    }
    

    枚举

    /**
     * 不仅可以解决线程同步,还可以防止反序列化
     * 线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化调用
     */
    public enum Mgr08 {
        INSTANCE;
        public void m() {}
        public static void main(String[] args) {
            for (int i = 0; i < 100; i++) {
                new Thread(() -> {
                    System.out.println(Mgr08.INSTANCE.hashCode());
                }).start();
            }
        }
    }
    
    • 各位看官,以上8种单利模式你们都见过么,你还敢说你们懂单例模式么?
    • 其实单例模式不是一个简单的设计模式。
    • 推荐使用Mgr01,因为简单
    • Mgr06、Mgr07 和 Mgr08比较完美

    ————————————————————
    坐标帝都,白天上班族,晚上是知识的分享者
    如果读完觉得有收获的话,欢迎点赞加关注

    相关文章

      网友评论

          本文标题:单例模式

          本文链接:https://www.haomeiwen.com/subject/ibtanktx.html