黑马程序员技术交流社区

标题: 如何理解双重判断的效率问题? [打印本页]

作者: 朝花夕拾    时间: 2012-11-18 22:15
标题: 如何理解双重判断的效率问题?
本帖最后由 张雄 于 2012-11-22 22:30 编辑

现在有如下代码:
If(instance == null) {
synchronized(Single.class) {
        if(instance == null) {
instance = new Single();
        }
}
}
return instance;
本人觉得在该代码中,执行一次后则该同步代码块结束,双重判断不存在效率问题,求高手解释!!!
作者: 张利    时间: 2012-11-18 23:22
如果没有外层的判断,则每一次线程到这里之后都需要一个个的来等待锁,比较麻烦;
而加了外层判断后,就是刚开始的线程判断需要等待,在创建实例之后的线程再来访问的时候,直接就可以
跳过去了,而不需要锁了
作者: 朝花夕拾    时间: 2012-11-18 23:32
首先,如果把if(install==null) 这一句转换成汇编代码后只有一句 JZ XXX
sync代码块相比较if判断,汇编指令还会多些,
而电脑每秒执行的指令数几十上百万条
所以大家误认为的判断会造成效率问题是不对的,单纯的判断是不会造成效率问题的,
但是,不必要的操作是被认为是影响效率的,
比如LZ的代码,如果这段代码只被一处调用,这样写是完全没有必要的,而且是算效率问题的
只有在多个线程同时调用这段代码时,才可以这样写,
不过想new instance()这样的操作一般都是使用单例模式,而不是这样的sync块+多重判断
作者: 凊係柈泩    时间: 2012-11-18 23:47
我是这样理解的,首先我们先看一下懒汉式原有的代码
if(instance==null){
instance = new Single();
}
假如我们使用了多线程技术,线程A进来了判断instance等于null满足,执行权被切换走,等待
线程B进来了,判断instance等于null线程B也等待,假如A线程获得执行权创建了对象,C线程不在
判断标记直接又创建了对象,这样内存中就存在了两个对象。
如果我们在方法上加了同步函数,A线程进来创建了对象并返回,B线程进来也要判断锁,instance不为
null这样我们就解决了问题,但是其他线程进来都需要判断锁这样效率很低。
If(instance == null) {
synchronized(Single.class) {
        if(instance == null) {
instance = new Single();
        }
}
}
return instance;
我们就可以用同步代码块的
形式创建锁,但是这样和同步函数是一样的,所以在同步代码块上加了一层判断,A线程执行完毕,B线程在
第一层判断不为null就不在执行了,这样做提高了效率。
作者: 陈军    时间: 2012-11-19 11:29
其实这个也不太好的。如:
class Single   
{   
    private static Single singleObj = null;     
    private Single(){ }     
    public static  Single getSingleInstance() {   
            if(singleObj==null){                                //AA
                    synchronized(Single.class){
                             if(singleObj==null )  //BB
                                    singleObj = new Single();
                    }
            }            
        return singleObj;                 //CC
    }   
}
可是实际上这个还是有问题的。
假设线程1执行到了AA那里,它判断对象为空,于是线程1执行到BB 去初始化这个对象,但初始化是需要耗费时间的,

但是这个对象的地址其实已经存在了。此时线程2也执行到了AA那里,它判断不为空,于是直接跳到CC得到了这个对象。

但是,这个对象还没有被完整的初始化!得到一个没有初始化完全的对象有什么用!!没有意义。

最好的单例设计就是内部类:

代码如下:

class Single {
        private Single(){}
        
        private static class SingleHolder{
                public static final Single instance=new Single();
        }
        
        public static Single getInstance(){
                return SingleHolder.instance;
        }
        
}
这种方式兼具饿汉式和懒汉式优点。而且,JLS(Java Language Sepcification)会保证这个类的线程安全。

具体请看我的帖子:  http://bbs.itheima.com/thread-30600-1-1.html





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2