美文网首页
单例模式

单例模式

作者: ilaoke | 来源:发表于2017-08-10 17:44 被阅读6次

    Ensure a class only has one instance, and provide a global point of access to it.

    确保一个类只有一个实例,并且提供一个全局指针访问它

    各种单例类的共同点:

    1. 私有构造器
    2. 私有的静态实例变量
    3. public的静态方法,返回单例对象

    单例1

    /**
     * 基础单例类
     */
    public class BasicSingleton {
        private static BasicSingleton instance;
    
        // 私有构造器,确保不会在该类之外实例化
        private BasicSingleton() {
        }
    
        public static BasicSingleton getInstance() {
            // Lazy initialization 懒加载
            if (instance == null) {
                instance = new BasicSingleton();
            }
            return instance;
        }
    }
    

    注意构造器是private的,该单例的问题:不是线程安全的,当有多个线程调用getInstance()方法时,可能会产生多个实例。

    单例2 - 线程安全 - 粗粒度

    /**
     * 线程安全单例
     */
    public class ThreadSafeSingleton {
    
        private static ThreadSafeSingleton instance;
    
        // 私有构造器,确保不会在该类之外实例化
        private ThreadSafeSingleton() {
        }
    
        // synchronized方法
        public static synchronized ThreadSafeSingleton getInstance() {
            // Lazy initialization 懒加载
            if (instance == null) {
                instance = new ThreadSafeSingleton();
            }
            return instance;
        }
    }
    

    线程安全单例,该单例的问题:在多线程情况下,会在getInstance()方法处形成阻塞。

    单例3 - 线程安全 - 细粒度

    /**
     * 加载线粒度的锁
     */
    public class ThreadSafeSingleton2 {
        private static ThreadSafeSingleton2 instance;
    
        // 私有构造器,确保不会在该类之外实例化
        private ThreadSafeSingleton2() {
        }
    
        public static ThreadSafeSingleton2 getInstance() {
            if (instance == null) {
                // check 1
                synchronized (ThreadSafeSingleton2.class) {
                    // double checked locking,再次判空是需要的
                    // check 2
                    if (instance == null) {
                        instance = new ThreadSafeSingleton2();
                    }
                }
            }
            return instance;
        }
    }
    

    首先要明白细粒度的意思,单例2 - 线程安全 - 粗粒度 例子中,每次进入getInstance() 方法都需要同步,太浪费。这个例子中,判断完是否为空后再同步,这样大家需要同步的机会就大大减少了。同时要注意,再次判断是否为空是需要的,如果两个线程同时到达check 1,如果没有check 2的判空,就会产生两个实例。

    单例4 - Eager initialization

    /**
     * 提前初始化单例
     */
    public class EagerInitializedSingleton {
        // 类加载即创建单例
        private static final EagerInitializedSingleton instance = new EagerInitializedSingleton();
    
        // 私有构造器,确保不会在该类之外实例化
        private EagerInitializedSingleton() {
        }
    
        public static EagerInitializedSingleton getInstance() {
            return instance;
        }
    }
    

    该单例是线程安全的,但问题是即使在不需要实例时,也被初始化了。

    单例5 - 静态块单例

    /**
     * 静态块单例
     */
    public class StaticBlockSingleton {
        private static StaticBlockSingleton instance;
    
        private StaticBlockSingleton() {
        }
    
        // 静态块的作用是,添加异常处理
        static {
            try {
                instance = new StaticBlockSingleton();
            } catch (Exception e) {
                throw new RuntimeException("Exception occured in creating singleton instance");
            }
        }
    
        public static StaticBlockSingleton getInstance() {
            return instance;
        }
    }
    

    该单例的问题同 单例4 - Eager initialization,即使在不需要实例时也被初始化了,不同的是增加了异常处理的机会。

    单例6 - Bill Pugh - 最佳实践

    /**
     * 通过内部静态类来避免提前实例化和线程安全问题,
     * 从而达到只在需要时才被加载并且没有线程安全问题
     */
    public class BillPughSingleton {
    
        // 私有构造器,确保不会在该类之外实例化
        private BillPughSingleton() {
        }
    
        // 内部静态类
        private static class SingletonHelper {
            private static final BillPughSingleton INSTANCE = new BillPughSingleton();
        }
    
        public static BillPughSingleton getInstance() {
            // 此时才会加载SingletonHelper类,然后创建单例对象
            return SingletonHelper.INSTANCE;
        }
    }
    

    内部静态类,只有在使用时才会被加载,然后创建单例。避免了提前创建和线程安全的问题。


    参考:Java Singleton Design Pattern Best Practices with Examples

    相关文章

      网友评论

          本文标题:单例模式

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