A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 邱成 中级黑马   /  2012-9-14 07:27  /  2022 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 邱成 于 2012-9-14 22:11 编辑

/*
单例设计模式。


*/
//饿汉式。
/*
class Single
{
        private static final Single s = new Single();
        private Single(){}
        public static Single getInstance()
        {
                return s;
        }
}
*/


//懒汉式

class Single
{
        private static Single s = null;
        private Single(){}


        public static  Single getInstance()
        {
                if(s==null)//为什么
                {
                        synchronized(Single.class)
                        {
                                if(s==null)
                                        //为什么
                                        s = new Single();
                        }
                }
                return s;
        }
}
这是毕老师在第十一天的代码关于单例设计模式的,请问懒汉式中为什么要用双重判断啊

评分

参与人数 1黑马币 +10 收起 理由
刘芮铭 + 10 这个问题大家需要弄清楚

查看全部评分

5 个回复

倒序浏览
class Single
{
         private static Single s = null;
         private Single(){}


        public static  Single getInstance()
         {
                 if(s==null)//为什么-----------(1)
                 {
                         synchronized(Single.class)
                         {
                                 if(s==null)
                                         //为什么-------------(2)
                                         s = new Single();
                         }
                 }
                 return s;
         }
}这是毕老师在第十一天的代码关于单例设计模式的,请问懒汉式中为什么要用双重判断啊


我的理解是:(2)的作用是:  s是空的才可以new对象
                  (1)的作用是:  为减少对锁的重复判断


假如把(1)去掉,当线程1已经new了一个对象之后,每个线程进来都要经过 synchronized(Single.class)
                                                                                                                                   {
                                                                                                                                                  if(s==null)
                                                                                                                           // s不为空,不new对象。
这样对锁的重复判断,很占用资源



把(1)加上去后,当线程1已经new了一个对象之后,  每个线程进来 ,
                                                                              public static  Single getInstance()
                                                                                      {
                                                                                                     if(s==null)//为什么----(1)-----在这里就判断s不为空,不new对象,不执行下面的
                                                                                                                               语句了,这样就减少了对锁的重复判断。

                                                                                     {
                                                                                                                    synchronized(Single.class)
                                                                                                                    {
                                                                                                                                   if(s==null)
                                                                                                          //为什么-------------(2)
                                                                                                          s = new Single();

评分

参与人数 1技术分 +1 收起 理由
刘芮铭 + 1 回答的不错,很有条理

查看全部评分

回复 使用道具 举报
本帖最后由 廖智 于 2012-9-14 10:22 编辑

//懒汉式

class Single
{
        private static Single s = null;
        private Single(){}


        public static  Single getInstance()
        {
                if(s==null)//为什么 ----->(1)这里判断s是否为空,第一次判断这里时s为空,满足,然后会判断锁。第二次判断时s已经new对象了,所以判断不为null,就不会再判断下面的锁了。
                {
                        synchronized(Single.class)
                        {
                                if(s==null)//为什么 ----->(2)第一次判断锁里的s,s为空,满足,给s赋值。这时s有值了,然后再次判断(1)时s是不为空的,所以就不用执行下面的锁了。这样就减少

了对锁的判断。节省了资源。

                                        s = new Single();
                        }
                }
                return s;
        }
}

所以说,用双重判断能减少对锁的判断,节省了资源的占用,可以起到代码优化的作用。

评分

参与人数 1技术分 +1 收起 理由
刘芮铭 + 1 很有条理

查看全部评分

回复 使用道具 举报
class Single
{
         private static Single s = null;
         private Single(){}


        public static  Single getInstance()
         {
                 if(s==null)//(1)第一次进来,S为null                                        //当要new对象时判断s不为null;不需要判断锁了  
                 {


                         synchronized(Single.class)//(2)然后判断锁        //如果没有外面的判断,那么new对象时要判断锁
                         {
                                 if(s==null)//(3)再次判断s为null                //提高安全性
                                         //为什么
                                         s = new Single();//(4)new 对象,S不为null
                         }
                 }
                 return s;
         }
}


双重判断是为了以后new对象时即保证安全性,又节省判断次数

评分

参与人数 1技术分 +1 收起 理由
刘芮铭 + 1 新手回答,很有条理,多多鼓励.

查看全部评分

回复 使用道具 举报
本帖最后由 范泰洋 于 2012-9-14 10:17 编辑

class Single2{

private Single2(){};

private static Single2 s2 = null;

public static Single2 getSingle2(){

--->c当a释放返回了对象,释放了手中的锁,c就要进来了,但是发现s2已经不为null,条件不满足。

if(s2==null){

--->b判断s2为null试图想要拿到锁,但是条件不满足。

synchronized(Single2.class) {//这个编译生成的文件是唯一的,用这个来做一把锁。

if(s2==null){//当a和b同时调用这个方法的时候,假如a条件都满足了拿到了锁,突然睡着了,这时b就会试图想要拿锁,但是这时锁还在a的手里,a还没有释放手中的锁,所以进不来。

--->a手中拿着single.class这把锁。

s2 = new Single2();

}

}

}

return s2;//当a创建了对象并返回了,就会释放手中的锁,这时b拿到了锁,但是经过判断,s2已经指向了一个对象,已经不为null了,所以不会在创建对象了。当c进来的时候经过判断s2不为null了,就不满足条件了连判断锁都省去了!

}

}

public class SingleDemo2 {

/**

* @param args

*/

public static void main(String[] args) {

// TODO Auto-generated method stub

Single2 s1 = Single2.getSingle2();

Single2 s3 = Single2.getSingle2();

System.out.println(s1.equals(s3));

}

}

评分

参与人数 1技术分 +1 收起 理由
刘芮铭 + 1 赞一个!

查看全部评分

回复 使用道具 举报
懒汉式在多线程访问是就会产生安全隐患。所以要用同步。
同步后,每个线程想获取实例都要判断一次锁,所以效率低。
所以用双重判断解决效率低的问题。如果已经有了Single的实例,s就不等于null,也就不用再进去判断锁了。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马