zoukankan      html  css  js  c++  java
  • 设计模式-单例模式的5种实现

    单例模式是开发中使用频率极高的一个模式,比如Spring的bean默认就是单例的。

    概念

    单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

    单例模式有一下特点:

    1. 单例类只有一个实例。
    2. 单例类必须自己创建自己的唯一实例。
    3. 单例类必须给所有其他对象提供这一实例。

    实现方式

    一般意义上来讲单例模式有两种实现方式,懒汉模式和饿汉模式。

    饿汉模式

    public class Singleton {  
        private static Singleton instance = new Singleton();  
        private Singleton (){}  
        public static Singleton getInstance() {  
            return instance;  
        }  
    }  
    

    类加载自动初始化对象,不是lazy init ,系统启动的压力增大。

    懒汉模式

    public class Singleton {  
        private static Singleton instance;  
        private Singleton (){}  
    
        public static Singleton getInstance() {  
            if (instance == null) {  
                instance = new Singleton();  
            }  
            return instance;  
            }  
    }  
    

    典型的懒汉模式,在需要初始化使用单例对象时才决定是否初始化,减轻了启动的负担,但是无法在多线程环境下运行,可能会导致产生多个实例。

    改进版的懒汉模式

    为了解决懒汉模式在多线程情况的问题,我们使用synchronized关键词同步代码,不就可以避免了同步问题了吗?

    public class Singleton {  
        private static Singleton instance;  
        private Singleton (){}  
        public static synchronized Singleton getInstance() {  
            if (instance == null) {  
                instance = new Singleton();  
            }  
            return instance;  
        }  
    }  
    

    这种改良方式的确会解决多线程的问题,但同时synchronized会导致每次方法调用时锁住Singleton实例一次,性能消耗太大。而且instance一旦初始化后,同步锁更加拖累效率。

    双重锁定的懒汉模式

    public class Singleton {  
        private volatile static Singleton singleton;  
        private Singleton (){}  
        public static Singleton getSingleton() {  
            if (singleton == null) {  
                synchronized (Singleton.class) {  
                    if (singleton == null) {  
                        singleton = new Singleton();  
                    }  
                }  
            }  
        return singleton;  
        }  
    }  
    

    这种模式避免了域在被初始化之火访问这个域的锁定开销。这种模式的基本思想是:
    第一次检查时看看有没有锁定,看一看这个域是否已被初始化了;第二次检查时有锁定,只有当第二次检查时表明这个域没有被初始化,才开始进行初始化。

    这种模式既规避了延迟加载也避免了重复加锁带来的额外性能消耗。

    静态内部类

    public class Singleton {  
        private static class SingletonHolder {  
            private static final Singleton INSTANCE = new Singleton();  
        }  
        private Singleton (){}  
        public static final Singleton getInstance() {  
            return SingletonHolder.INSTANCE;  
        }  
    }  
    

    当getInstance方法第一次调用时,第一次读取SingletonHolder.INSTANCE,导致SingletonHolder类得到初始化,这种方式并没有使用任何线程同步的机制,就保证了一次访问域代码。延迟初始化没有增加访问成本,这个方法值得推荐。

    结论

    5种方式,相对比较推荐第4种和第5种,做到了延迟加载,也没有引入额外的问题和性能开销。

  • 相关阅读:
    对于MVVM的理解
    HTML a标签的连接让浏览器在新的标签页面打开的方法
    extjs 4 tab panel得strip在IE下右偏解决办法
    python 学习心得
    qt 调试不可用或断点失效的解决办法(CDB找不到)
    C# List<> add函数总是覆盖List中原有元素的解决办法
    qt 怎么创建子对话
    C# 添加了 reference 后 仍然报 找不到命名空间的问题
    qt项目搬到另一台电脑出错的解决办法
    工厂模式生成构造函数带参数的对象时的解决办法(Assembly.Load(path).CreateInstance)
  • 原文地址:https://www.cnblogs.com/jason0529/p/6561017.html
Copyright © 2011-2022 走看看