美文网首页
Java面试向:脑图单例模式

Java面试向:脑图单例模式

作者: 拾识物者 | 来源:发表于2018-09-21 10:07 被阅读15次

    单例模式,绝对是面试时被问到最多的设计模式。如果搜索网上的java单例模式,这篇文章是说得最全面和深入的:

    你真的会写单例模式吗——Java实现

    本文的脑图就是这篇文章的总结和精炼:百度脑图

    脑图截图

    单例模式概念上是很简单的:提供和限制全局唯一的对象。复杂的是现实问题和实现方法。

    衡量Java单例模式的好坏有几个方面:

    • 多线程安全:多个线程调用单例方法不会产生多个对象才是安全的,才达到单例模式的目的。
    • 延迟创建对象:单例模式创建的对象可能初始化一次需要耗费很多资源,内存、IO等,因此能不创建就不创建,只在调用单例方法的时候才创建。
    • 简单易懂:有几种写法还是有些复杂和反直觉的,当然为了面试,可以背一背,研究一下背后的原理。比如volatile关键字,就值得研究一下。
    • 防反射和序列化:从安全角度考虑,防止反射创建多个对象,防止反序列化时生成另一个对象。其实只有枚举法天生具有这两个能力,其他方法都可以用同样的方式达到这个目的。

    另外,《游戏设计模式》一书中对单例模式的剖析很有趣,作者建议你不用单例模式。为什么?最直接的一个原因是:单例模式本质上就是一个全局变量啊!中文版传送门

    以下是几种实现代码,脑图上放代码看起来有些费劲。

    先定义一个获取方法的main方法来进行一个简单的测试,目的是判断是否延迟加载。

    public class DemoSingleton {
        public static void main(String[] args) {
            SingletonClass.getInstance();
        }
    }
    

    另一个测试,简单的测试一下是否是线程安全的,如果输出了两个构造函数的log那么肯定是不安全的。由于线程调度的不确定性,可能需要调整一下线程的数量,再多试几次。最好玩的是第三个方法中,去掉volatile关键字或者去掉一层判断,可以更好地理解为什么要写这么多代码来保证线程安全。

    public class DemoSingleton {
        public static void main(String[] args) {
            for (int i = 0; i < 25; i++) {
                new Thread(new Runnable(){
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(1000);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        SingletonClass.getInstance();
                    }
                }).start();
            }
        }
    }
    
    1. 定义静态字段时直接初始化:简单;线程安全;不延迟
    class SingletonClass {
        private static SingletonClass instance = new SingletonClass();
        public static SingletonClass getInstance() {
            System.out.println("getInstance()");
            return instance;
        }
        private SingletonClass() {
            System.out.println("new SingletonClass");
        }
    }
    // 输出
    // new SingletonClass
    // getInstance()
    
    1. 静态方法中简单判断唯一性:简单;线程不安全;延迟
    class SingletonClass {
        private static SingletonClass instance;
        public static SingletonClass getInstance() {
            System.out.println("getInstance()");
            if (instance == null) {
                instance = new SingletonClass();
            }
            return instance;
        }
        private SingletonClass() {
            System.out.println("new SingletonClass");
        }
    }
    // 输出
    // getInstance()
    // new SingletonClass
    
    1. 静态方法中判断唯一性考虑线程安全:复杂;线程安全;延迟
    class SingletonClass {
        private static volatile SingletonClass instance;
        public static SingletonClass getInstance() {
            System.out.println("getInstance()");
            if (instance == null) {
                synchronized(SingletonClass.class) {
                    if (instance == null) {
                        instance = new SingletonClass();
                    }
                }
            }
            return instance;
        }
        private SingletonClass() {
            System.out.println("new SingletonClass");
        }
    }
    // 输出
    // getInstance()
    // new SingletonClass
    
    1. 静态内部类:简单;线程安全;延迟
    class SingletonClass {
        private static class SingletonHolder {
            private static volatile SingletonClass instance = new SingletonClass();
        }
        public static SingletonClass getInstance() {
            System.out.println("getInstance()");
            return SingletonHolder.instance;
        }
        private SingletonClass() {
            System.out.println("new SingletonClass");
        }
    }
    // 输出
    // getInstance()
    // new SingletonClass
    
    1. 枚举法:诡异;线程安全;不延迟
    enum SingletonClass {
        INSTANCE;
        public static SingletonClass getInstance() {
            System.out.println("getInstance()");
            return INSTANCE;
        }
        private SingletonClass() {
            System.out.println("new SingletonClass");
        }
    }
    // 输出
    // new SingletonClass
    // getInstance()
    

    拜拜,煮面时顺溜

    参考资料
    http://www.tekbroaden.com/singleton-java.html
    https://gpp.tkchu.me/singleton.html

    相关文章

      网友评论

          本文标题:Java面试向:脑图单例模式

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