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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 杨毅 黑马帝   /  2012-2-15 20:24  /  2034 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 杨毅 于 2012-2-15 23:21 编辑

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 ;
        }
}


本人新手,刚开始学,看到基础视频里面讲解的懒汉式单例模式时,不是很明白为什么在synchronized 里还要判断一次 if(s==null) ,不是已经判断过了吗?个人觉得没什么必要,去掉没区别啊?可以去掉么? 求解释 .

5 个回复

正序浏览
李杨 发表于 2012-2-15 22:04
同学你好:
          首先你需要明白synchronized的作用,意思是当线程得到了cpu分配的随机时间片后并获得了 ...

额...  我说的了解就是懂了 ..  先没考虑到有多个线程挂在第一个if 后面..       还是谢谢你的详细解释  
回复 使用道具 举报
本帖最后由 李杨 于 2012-2-15 22:09 编辑

同学你好:
          首先你需要明白synchronized的作用,意思是当线程得到了cpu分配的随机时间片后并获得了锁,那么这个线程就可以执行同步代码块中的代码,没有得到时间片的线程只能等待cpu分配.



首先说明:线程拥有了执行权其实是得到cpu为该线程分配了随机时间片才有权执行的.

为了可以让你充分的明白而不是了解,举例: 线程数量 3个 分别是线程 a, b, c

当三个线程启动后,b线程先被cpu分配了随机时间片. 当b线程执行到 2 的位置的时候(即在刚执行完外面的if和同步代码块之间的位置的
时候时间片用完了),就会等待时间片到来.

这时a线程得到了随机时间片并开始执行,执行到同步代码块并且拿到了锁,在拿到锁之后却还没来得及执行里面的if的时候,a线程的时间片用完了在3的位置等待cpu的时间片.

这时c线程得到了cpu分配的时间片开始执行,当c线程在刚进去方法却还没来得执行外面的if的时候时间片用了,就在1的位置等待时间片到来.

这时a线程得到时间片开始运行,开始判断里面的if判断对象还没有创建,则创建
了对象然后返回了,这个时候在2位置的b线程得到了时间片,b线程开始运行,并进入了同步代码块那了锁,判断对象已经存在了(这位同学你
要注意的地方就在这!!!!!!)
就直接返回,这时在1位置的c线程得到时间片,开始判断外面if发现对象已经存在了就不执行同步代码块了就直
接返回对象了.

同学希望你能看懂过程....不要了解!

加油!!!
回复 使用道具 举报
mnisummer 发表于 2012-2-15 20:42
可以写成这样:
public static Single getInstance()
         {

了解了 ,谢谢
回复 使用道具 举报
public static Single getInstance()
        {
                if(s==null)
                {
                        synchronized(Single.class)
                        {
                                if(s==null)
                                s = new Single();                        
                        }
                }
                return s ;
        }
我认为是这么理解:首先N多线程进来访问getInstance(),
判断s是否存在根据优先级访问同步代码块接着判断执行创建新对象。
但是如果执行完后,对象存在了。接着如果还有N条再次进入getInstance()
根据第一个if就不用去访问内部代码。节省时间。
回复 使用道具 举报
可以写成这样:
public static Single getInstance()
         {
                         synchronized(Single.class)
                         {
                                 if(s==null)
                                 s = new Single();                        
                        }
                 return s ;
         }
,但是只要有一个创建出一个对象后,其他线程执行到这个方法,都会逐个去得到锁,进入if判断,这样会性能会降低。我们在锁的外面再加一个if(s==null),这样,只要s有了指向,其他线程执行这个方法,那么第一个if就不能进去,从而减少了判断锁的次数,性能得到了提高。

还有,同步代码块里的if不能去掉。如果去掉了,当两个线程执行到synchronized处时,线程A得到了锁,线程B在等待,当线程A创建了对象后,释放了锁,线程B将会得到锁,又会创建对象。这样就不能保证单例了。

建议使用两个if,中间夹着synchronized这种写法
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马