zoukankan      html  css  js  c++  java
  • 单例模式中的双重校验锁

    // 单线程的时候
    class Foo {
        private Helper helper = null;
        public Helper getHelper() {
            if (helper == null) {
                helper = new Helper();
            }
            return helper;
        }
    
    }

    这段在使用多线程的情况下无法正常工作。在多个线程同时调用getHelper()时,必须要获取,否则,这些线程可能同时去创建对象,或者某个线程会得到一个未完全初始化的对象。

    锁可以通过代价很高的同步来获得,就像下面的例子一样。

    //这样写虽然正确,但是粗暴地把getHelper锁住了,这样代价很大
    class Foo {
        private Helper helper = null;
        public synchronized Helper getHelper() {
            if (helper == null) {
                helper = new Helper();
            }
            return helper;
        }
    
    }

    只有getHelper()的第一次调用需要同步创建对象,创建之后getHelper()只是简单的返回成员变量,而这里是无需同步的。 由于同步一个方法会降低100倍或更高的性能[2], 每次调用获取和释放锁的开销似乎是可以避免的:一旦初始化完成,获取和释放锁就显得很不必要。许多程序员一下面这种方式进行优化:

    1. 检查变量是否被初始化(不去获得锁),如果已被初始化立即返回这个变量。
    2. 获取锁
    3. 第二次检查变量是否已经被初始化:如果其他线程曾获取过锁,那么变量已被初始化,返回初始化的变量。
    4. 否则,初始化并返回变量。
    //这种双重检查锁定就很好地解决问题,避免每次调用都要获取锁
    class Foo {
        private Helper helper = null;
        public Helper getHelper() {
            if (helper == null) {
                synchronized(this) {
                    if (helper == null) {
                        helper = new Helper();
                    }
                }
            }
            return helper;
        }
    
    }
  • 相关阅读:
    Yii “CDbConnection failed to open the DB connection: could not find driver"解决办法
    安装多个PHP环境会导致phpinfo和php -v中查看到的PHP版本不一致
    sql pivot、unpivot和partition by用法
    sql把字符数组转换成表
    sql获取数组指定元素
    sql获取数组长度
    Razor基础语法
    ADO.NET基础
    Asp.Net网站统一处理错误信息
    WebApp页面开发小结
  • 原文地址:https://www.cnblogs.com/diaoniwa/p/7299746.html
Copyright © 2011-2022 走看看