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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© Jim-剣◆﹏ 高级黑马   /  2013-9-27 13:42  /  1530 人查看  /  6 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

  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这种?


评分

参与人数 1技术分 +1 收起 理由
杨增坤 + 1

查看全部评分

6 个回复

倒序浏览
本帖最后由 jìng╮煜 于 2013-9-27 14:11 编辑

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

评分

参与人数 1技术分 +1 收起 理由
乔兵 + 1

查看全部评分

回复 使用道具 举报
  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. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
杨增坤 + 1

查看全部评分

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

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

而对于执行不执行Return S,还没弄清

评分

参与人数 1黑马币 +1 收起 理由
乔兵 + 1

查看全部评分

回复 使用道具 举报
第一种:应该不会立即执行return,而是线程等待,等待锁被释放。
第二种:就会执行return,因为一判断不为空,就说明此对象已经创建,不需要创建,直接返回已经创建好的对象即可。省去了判断锁

希望对你有帮助!

评分

参与人数 1技术分 +1 收起 理由
乔兵 + 1

查看全部评分

回复 使用道具 举报
前一段程序的问题,如果锁没开,其他线程是出于等待状态的。等待拿到锁的线程执行同步结束后释放cpu执行权。

后一段程序的问题:
判断之前加上if判断语句,如果第一次判断为空的话,某一线程必须会往下执行直到创建一个对象:对象没有被创建,又怎么会有被取走的可能。
能解决效率问题是:因为创建对象需要在堆内存中开辟空间并且对对象进行初始化,程序执行到才创建对象,可以节约内存资源。如果执行到后第一次某一线程创建了对象,下一次某一线程执行则判断如果对象存在就直接使用对象,就不必拿到锁后再去进行对象是否存在的判断。

评分

参与人数 1技术分 +1 收起 理由
乔兵 + 1

查看全部评分

回复 使用道具 举报
饿汉初始化根本不会存在线程安全问题,但开销是个问题,因为懒汉模式的使用理念是"用时才初始化",饿汉模式则是"不管用不用都初始化",这本身是和业界流行的资源使用习惯相违背的.

评分

参与人数 1技术分 +1 收起 理由
乔兵 + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马