黑马程序员技术交流社区

标题: 单例的多线程安全问题 [打印本页]

作者: 李东梁    时间: 2014-4-14 19:48
标题: 单例的多线程安全问题
  1. class Single
  2. {
  3.         private static Single s = null;
  4.         private Single(){}
  5.         public static  Single getInstance()
  6.         {
  7.                 if(s==null)<font color="Red">//第一次判断是否为空</font>
  8.                 {
  9.                         synchronized(Single.class)
  10.                         {
  11.                                 if(s==null)<font color="Red">//第二次判断是否为空</font>
  12.                                 {
  13.                                         s = new Single();
  14.                                 }
  15.                         }
  16.                 }
  17.                 return s;
  18.         }
  19. }
复制代码

两次判断的目的就是为了提高效率,第一次已经判断过了,第二次是不是不用判断了,能进来的不都是非空的吗,加了第二次判断,不又降低效率了吗?
作者: 月光海    时间: 2014-4-14 20:01
不是这样的,当一个线程判断为null之后,如果被CPU切走了,另一个线程进来了,然后进入到同步代码块中,new一个对象出去了,然后刚刚躺下的线程回来之后就不会再判断前面的if了,就会进入到同步代码块中,如果里面没有if的话,就又new了一个对象,就不是单例了
作者: yanzhendong    时间: 2014-4-14 20:24
额,这样做恰好提高了效率,楼主可以这样想,假如这个单例对象已经存在,因为有第一个if,线程直接就能取走单例对象,而没第一个if,线程还要先获得锁,再判断s是否为空,然后才能取走单例对象,这样效率反而下降了
作者: kuroro自走核炮    时间: 2014-4-14 20:38
三个阶段 1 判断是否为空 2 判断里面是否有人 3 判断是否为空
如果没有第三个阶段
第一个线程进入,1判断,是空,2判断,没人,进去以后,睡了。
第二个线程进入,1判断,是空,2判断,有人,在2号位置上等。
第一个线程醒了,建立对象,拍拍屁股走了。里面不是空了。
第二个线程,2判断,没人,进去以后又做了S=new Single();这个动作。如果有第三个判断的话,非空,就不会有创建动作了。
所以第三个是有用的,不能少。
作者: 疯狂沙漠    时间: 2014-4-14 20:42
假如现在有2个线程A和B,当A线程执行到了同步块时被挂起,执行权被B夺走了,B线程执行到了第一个if判断的时候,这时B被挂起,执行权被A夺走,A线程在同步块中继续执行创建了对象,释放锁后,被B夺走执行权,B线程就进入了同步块,遇到了第二次if判断,发现已经有对象了,就不再执行创建对象的语句。若是还有第3条线程进来,会先执行第一个if,发现有对象了就不会再继续执行以下代码。
总结:第一条线程会执行完所有代码,第二条线程执行到第二个if就结束,之后的线程执行到第一个if判断就结束
作者: 李东梁    时间: 2014-4-14 21:05
月光海 发表于 2014-4-14 20:01
不是这样的,当一个线程判断为null之后,如果被CPU切走了,另一个线程进来了,然后进入到同步代码块中,new ...

懂了,谢谢哈




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