zoukankan      html  css  js  c++  java
  • 单例模式(Singleton)

       单例模式是一种常用的设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候,整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,显然,这种方式简化了在复杂环境下的配置管理。
    常见单例模式:懒汉式,饿汉式等。

    懒汉式式单例(Singleton)

          优点:没有加锁,执行效率会提高。 缺点:类加载时就初始化,浪费内存。

    public class Singleton {
        private static Singleton instance = new Singleton();
        private Singleton (){}  //构造方法私有化
        public static Singleton getInstance() {
            return instance;
        }
    }

    不安全饿汉式(UnsafeLazySingleton 

           严格意义上它并不算单例模式。这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。

    /**
     * @author buyi
     * 不安全的懒加载单例
     *
     * 不安全原因:
     * 1.假设A线程和B线程同时开始执行代码2,会new出两个对象
     * 1.假设A线程执行代码1的同时,B线程执行代码2。此时,线程A可能会看到instance引用的对象还没有完成初始化
     */
    public class UnsafeLazySingleton {
        private static Object instance;
        public Object getSingleton() {
            if (null == instance) {          //代码1
                instance = new Object();     //代码2
            }
            return instance;
        }
    }

    安全饿汉式(SafeLazySingleton)

            具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。优点:第一次调用才初始化,避免内存浪费。缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。

    /**
     * @author buyi
     * 安全的懒加载单例
     *
     * 待优化原因:
     * getSingleton()方法做了同步处理,synchronized将导致性能开销。如果getSingleton()方 法被多个线程频繁的调用,将会导致程序执行性能的下降。
     * 反之,如果getSingleton()方法不会被 多个线程频繁的调用,那么这个延迟初始化方案将能提供令人满意的性能。
     */
    public class SafeLazySingleton {
        private static Object instance;
        public synchronized Object getSingleton() {
            if (null == instance) {          //代码1
                instance = new Object();     //代码2
            }
            return instance;
        }
    }

    基于双重校验锁(DoubleCheckLazySingleton) 

    /**
     * @author buyi
     *
     * 万事大吉?
     *  在线程执行到##时,代码读取到instance不为null时,instance引用的对象有可能还没有完成初始化
     */
    public class DoubleCheckLazySingleton {
        private static Object instance;
        public Object getSingleton() {
            if (null == instance) {                                        //第一次检查   ##
                synchronized (DoubleCheckLazySingleton.class) {            //加锁
                    if (null == instance) {                                //第二次检查
                        instance = new Object();                           //实例化   
                    }
                }
            }
            return instance;
        }
    }
      问题根源:在于实例化new Object()时候,可以分解为三步骤 

          此时可能发生指令重排序2和3之间 

     

          那么线程A和线程B执行时序图可能为:

    
    
            A2和A3虽然重排序了,但Java内存模型的intra-thread semantics将确保A2一定会排在A4前面执行。因此,线程A的intra-thread semantics没有改变,但A2和A3的重排序,将导致线程B在B1处判断出instance不为空,线程B接下来将访问instance引用的对象。此时,线程B将会访问到一个还未初始化的对象。 

    双重检查锁升级版DoubleCheckSafeLazySingleton 

          基于双重检查锁和volatile(防止指令重排序)的单例模式

    /**
     * @author buyi
     *
     * 优化版基于双重检查锁和volatile的单例
     */
    public class DoubleCheckSafeLazySingleton {
        private  DoubleCheckSafeLazySingleton(){}//构造方法私有化
    private volatile static Object instance; public Object getSingleton() { 

    if (null == instance) {
    synchronized (DoubleCheckSafeLazySingleton.class){
    if (null == instance) {
    instance = new Object(); }
    } }
    return instance;
    } }

    静态内部类单例(Singleton

           SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。在延迟加载方面比懒汉式更好。

    public class Singleton {  
        private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
        }  
        private Singleton (){}  
        public static final Singleton getInstance() {  
        return SingletonHolder.INSTANCE;  
        }  
    }
  • 相关阅读:
    网络
    分区
    JavaScript概述
    CSS样式属性
    css选择器
    CSS的引入方式
    css介绍
    HTML结构
    常用标签
    HTML介绍
  • 原文地址:https://www.cnblogs.com/dyg0826/p/11284239.html
Copyright © 2011-2022 走看看