黑马程序员技术交流社区

标题: 多线程对懒汉式的效率低下的解释 [打印本页]

作者: Jim-剣◆﹏    时间: 2013-9-27 13:42
标题: 多线程对懒汉式的效率低下的解释
  1. class Single
  2. {
  3.         private static Single s = null;
  4.         private Single(){}


  5.         public static  Single getInstance()
  6.         {
  7.                 synchronized(Single.class)
  8.                 {
  9.                         if(s==null)
  10.                         s = new Single();
  11.                 }
  12.         return s;
  13.         }
  14. }
复制代码
加上锁可以解决安全问题,但是由此又导致了此段代码的执行效率低下,因为每次线程进来前都需要判断锁有没有开着,如果开着就线程就进入方法体,如果锁没开,问题一是:此时应该是返回对象S呢还是执不执行return s,我认为此时不执行,而是cpu执行权让出去,我理解对不对
  1. class Single
  2. {
  3.         private static Single s = null;
  4.         private Single(){}


  5.         public static  Single getInstance()
  6.         {
  7.                 if(s==null)
  8.                 {
  9.                         synchronized(Single.class)
  10.                         {
  11.                                 if(s==null)
  12.                                         s = new Single();
  13.                         }
  14.                 }
  15.                 return s;
  16.         }
  17. }
复制代码
判断之前增加一个if判断语句,如果为空,才进行锁判断,否则不进行锁判断,直接取走对象,问题还是一样,如果此时取走对象,对象还没建立会出现什么问题?
问题二:为什么这个能够解决效率问题?增加IF判断之后,线程每次进去之前要判断synchronized(Single.class)情况变为了判断IF语句而已,还是要判断,还是这两个语句的执行本身存在效率问题,例如执行IF语句需要1ms,而synchronized需要5ms这种?



作者: jìng╮煜    时间: 2013-9-27 14:04
本帖最后由 jìng╮煜 于 2013-9-27 14:11 编辑

可以像你这么理解,问题一,在同步代码块锁住的情况下,其他线程进入应该是需要wait的.(修改一下,不需要wait,因为此语句没有在synchronized 下)
问题二.关于锁,其实一个synchronized(Single.class)是一个方法,还要执行一串代码.(我估计是这样的)  如果是一个if,就仅仅是判断,仅仅是它本身而已.时间所耗长短自然就能看得出来
作者: code_geass    时间: 2013-9-27 14:05
  1. class Single
  2. {
  3.         private static Single s = null;
  4.         private Single(){}


  5.         public static  Single getInstance()
  6.         {
  7.                 if(s==null)//第一个判断不是说对象有问题,而是为了提高效率,因为每次都要判断锁。如果对象已经建立就直接返回s。
  8.                 {       
  9.                         synchronized(Single.class)//同步是解决安全问题
  10.                         {
  11.                                 if(s==null)//如果为空才建立对象,都是为了安全。
  12.                                         s = new Single();
  13.                         }
  14.                 }
  15.                 return s;
  16.         }
  17. }
复制代码

作者: Jim-剣◆﹏    时间: 2013-9-27 14:09
我思考了好一会,说说我的理解,引大神:
其实我觉得这个效率的问题是针对大并发量来说的,如果是小并发,在效率上不会有什么差别。
我们可以分析一下,两者的区别就在于:前者每次执行都存在两种情况(1)判断锁,(2)判断锁+判断if,
后者只需要在第一次创建完毕是要判断if+判断锁+判断if,以后都只存在判断if
当有大并发量的时候,前者的叠加效应会加大这个负担,而后者不存在叠加效应或者可以忽略不计

再者把一个大的方法声明为synchronized也会大大降低效率(此处来源某博客,具体可能涉及底层)

而对于执行不执行Return S,还没弄清
作者: 杨增坤    时间: 2013-9-27 14:53
第一种:应该不会立即执行return,而是线程等待,等待锁被释放。
第二种:就会执行return,因为一判断不为空,就说明此对象已经创建,不需要创建,直接返回已经创建好的对象即可。省去了判断锁

希望对你有帮助!
作者: .只影、天涯.    时间: 2013-9-29 17:09
前一段程序的问题,如果锁没开,其他线程是出于等待状态的。等待拿到锁的线程执行同步结束后释放cpu执行权。

后一段程序的问题:
判断之前加上if判断语句,如果第一次判断为空的话,某一线程必须会往下执行直到创建一个对象:对象没有被创建,又怎么会有被取走的可能。
能解决效率问题是:因为创建对象需要在堆内存中开辟空间并且对对象进行初始化,程序执行到才创建对象,可以节约内存资源。如果执行到后第一次某一线程创建了对象,下一次某一线程执行则判断如果对象存在就直接使用对象,就不必拿到锁后再去进行对象是否存在的判断。
作者: 周志龙    时间: 2013-9-29 18:38
饿汉初始化根本不会存在线程安全问题,但开销是个问题,因为懒汉模式的使用理念是"用时才初始化",饿汉模式则是"不管用不用都初始化",这本身是和业界流行的资源使用习惯相违背的.




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