黑马程序员技术交流社区

标题: 单例设计模式问题 [打印本页]

作者: 邱成    时间: 2012-9-14 07:27
标题: 单例设计模式问题
本帖最后由 邱成 于 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;
        }
}
这是毕老师在第十一天的代码关于单例设计模式的,请问懒汉式中为什么要用双重判断啊
作者: 叶征东    时间: 2012-9-14 08:24
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();

作者: 廖智    时间: 2012-9-14 08:46
本帖最后由 廖智 于 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;
        }
}

所以说,用双重判断能减少对锁的判断,节省了资源的占用,可以起到代码优化的作用。
作者: 覃宏海    时间: 2012-9-14 09:11
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对象时即保证安全性,又节省判断次数
作者: 范泰洋    时间: 2012-9-14 10:13
本帖最后由 范泰洋 于 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));

}

}

作者: 李菁    时间: 2012-9-14 10:36
懒汉式在多线程访问是就会产生安全隐患。所以要用同步。
同步后,每个线程想获取实例都要判断一次锁,所以效率低。
所以用双重判断解决效率低的问题。如果已经有了Single的实例,s就不等于null,也就不用再进去判断锁了。





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