zoukankan      html  css  js  c++  java
  • 查漏补缺系列:写单例时需要注意这三点!

    一、不简单的单例模式

    //以前学习的low版单例
    class LazySingleton{
        private static LazySingleton instance;
        private LazySingleton(){}
        public static LazySingleton getInstance() {
            if (instance==null){
                instance=new LazySingleton();
            }
            return instance;
        }
    }
    

    写单例需要注意一下三点:
    1)首先使用synchronized保证线程安全
    2)使用double check机制来防止重复创建实例,就是先去判断实例是否存在,如果不存在就执行同步代码块,那这样的话,多个线程进来,会只有一个申请锁成功,其他阻塞。同步代码块里面还有实例空判断,这是为了一个线程创建实例成功后,其他线程进来就会判断已经有了实例了就不会再去new对象。
    3)避免jvm指令重排是用了volatile修饰符。编译器(JIT),CPU 有可能对指令进行重排序,导致使用到尚未初始化的实例,可以通过添加volatile 关键字进行修饰,对于volatile 修饰的字段,可以防止指令重排。

    //这里使用的懒汉单例
    class LazySingleton{
        private volatile static LazySingleton instance;
        //这里注意不要漏了重写构造空的私有构造函数,这里容易忘
        private LazySingleton(){}
        public static LazySingleton getInstance() {
            if (instance==null){
                synchronized (LazySingleton.class){
                    if (instance==null){
                        instance=new LazySingleton();
                    }
                }
    
            }
            return instance;
        }
    }
    



    简单扩展(加分项):

    new Singleton()它并非是一个原子操作,事实上在JVM大概做了以下3个事情:
      1. 给 singleton 分配内存
      2. 调用 Singleton 的构造函数来初始化成员变量,形成实例
      3. 将singleton对象指向分配的内存空间(执行完这步 singleton才是非 null了)

      我们都知道,在JVM的JIT即时编译器中存在指令重排序的优化。正常执行是1-2-3,但发生指令重排后有可能是1-3-2。
      比如说有两个线程,线程一先执行了步骤3,在执行步骤2之前,此时线程二进来了,判断singleton实例时非null,注意此时singleton并未初始化,直接使用就报错了。

    这里涉及了JVM的内存加载流程和指令重排的知识,有机会后边再讲下。

  • 相关阅读:
    SQL Server 2008 数据库回滚到某个时间点
    SQL Server 2008以上误操作数据库恢复方法——日志尾部备份
    C# BindingSource
    何谓SQL Server参数嗅探
    mongodb获取具体某一天的查询语句
    给MongoDB添加索引
    MongoDB 学习笔记四 C#调用MongoDB
    Access MongoDB Data with Entity Framework 6
    Ruby 和 OpenSSL CA 证书的问题
    解决方法:配置群集时# gem install redis 报错:Unable to require openssl, install OpenSSL and rebuild ruby
  • 原文地址:https://www.cnblogs.com/mrmirror/p/13576844.html
Copyright © 2011-2022 走看看