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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 曹宇 中级黑马   /  2013-4-5 21:10  /  3138 人查看  /  11 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 曹宇 于 2013-4-5 21:13 编辑

毕老师说以下代码是死锁,并且演示了成功锁了。
为什么我在我机器上运行却锁不住呢?
我猜测应该是cpu的问题,我的是 i3的cpu。

不说这个锁不上的问题,最主要的问题是,既然是个死锁代码,在我的理解中,应该是运行到解不开的地方就会锁住,可是为什么
老师演示的时候在不同的地方锁住了呢?就是,有时候输出了十几行代码锁住了,有时候输出了好多行才锁住。
在我看来,既然是死锁,应该会在同一地方锁定的,为什么这个锁定却不是稳定的呢?

这点是为什么,想不透。
就跟错误的代码了,应该在错误的地方就终止了,可是却正常了一会才终止。。。。


头好晕啊,请大神们现身。。

谢谢了。


  1. class Test implements Runnable
  2. {
  3.         private boolean flag;
  4.         Test(boolean flag)
  5.         {
  6.                 this.flag = flag;
  7.         }

  8.         public void run()                                    //run方法中,老师用了嵌套同步代码块,使用了不同的对象来当锁
  9.         {
  10.                 if(flag)
  11.                 {
  12.                         while(true)             //老师说,带上无限循环,在一些机器上才会体现出锁,要不代码太短就执行完了。可是在我机器上就锁不住,无限循环不停止了。
  13.                         {
  14.                                 synchronized(MyLock.locka)
  15.                                 {
  16.                                         System.out.println(Thread.currentThread().getName()+"...if locka ");
  17.                                         synchronized(MyLock.lockb)
  18.                                         {
  19.                                                 System.out.println(Thread.currentThread().getName()+"..if lockb");                                       
  20.                                         }
  21.                                 }
  22.                         }
  23.                 }
  24.                 else
  25.                 {
  26.                         while(true)
  27.                         {
  28.                                 synchronized(MyLock.lockb)
  29.                                 {
  30.                                         System.out.println(Thread.currentThread().getName()+"..else lockb");
  31.                                         synchronized(MyLock.locka)
  32.                                         {
  33.                                                 System.out.println(Thread.currentThread().getName()+".....else locka");
  34.                                         }
  35.                                 }
  36.                         }
  37.                 }
  38.         }
  39. }


  40. class MyLock                                                         //类中放的静态对象,就是为了当锁用的。
  41. {
  42.         static Object locka = new Object();
  43.         static Object lockb = new Object();
  44. }

  45. class  DeadLockTest
  46. {
  47.         public static void main(String[] args)
  48.         {
  49.                 Thread t1 = new Thread(new Test(true));
  50.                 Thread t2 = new Thread(new Test(false));
  51.                 t1.start();
  52.                 t2.start();
  53.         }
  54. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
冯海霞 + 1

查看全部评分

11 个回复

倒序浏览
其实死锁并不是一种错误的代码,在运行和编译时期也都不会报错。在程序中加同步锁是为了解决安全隐患,即当程序运行到某段加同步锁的代码时,只允许一个线程进行访问,待此线程运行完这段代码并释放锁的时候,下一个线程才能拿到锁并运行此段代码。
而死锁是在用嵌套锁时,由于多线程同时进行,而互相抢到了对方的锁,使得双方都无法运行下去,而使程序处于阻塞状态。
就如毕老师举的例子:两个人去吃面,但是只有一双筷子,起初每人拿着一只筷子,然后你借给我一只,我就先吃一口;然后我又借给你一只,你也就吃一口……这样按部就班的来,大家就都能吃到面;但是如果双方都抢着吃,协商不下来,谁都不放自己手中的筷子,那谁都吃不了面。

评分

参与人数 1技术分 +1 收起 理由
冯海霞 + 1

查看全部评分

回复 使用道具 举报
死锁,锁住的时间理论是同一时间锁住,但是争夺cpu的访问,cpu访问时随机的
而且现在的电脑是双核的了,现在的都是4核的,所以
它说不定在什么时候锁住,这个事随机的,所以,不用纠结

评分

参与人数 1技术分 +1 收起 理由
冯海霞 + 1

查看全部评分

回复 使用道具 举报
  while(true)
                        {
                                synchronized(MyLock.locka)
                                {
                                        System.out.println(Thread.currentThread().getName()+"...if locka ");
                                        synchronized(MyLock.lockb)
                                        {
                                                System.out.println(Thread.currentThread().getName()+"..if lockb");                                       
                                        }
                                }
                        }
                }
                else
                {
                        while(true)
                        {
                                synchronized(MyLock.lockb)
                                {
                                        System.out.println(Thread.currentThread().getName()+"..else lockb");
                                        synchronized(MyLock.locka)
                                        {
                                                System.out.println(Thread.currentThread().getName()+".....else locka");
                                        }
                                }
                        }

这其实是cpu执行权分配的原因:
if locka
if lockb
else lockb
else locka
如果if locka先执行 到if lockb之前就失去了执行权,而else lockb获得执行权,他到else locka是又失去了执行权,执行权被if locka获得。
这是要执行if lockb但是else lockb的锁却没有释放所以进不去,而else locka要执行时又因为if locka没有释放锁所以不能执行。这样就很快进入死锁。

如果一开始if lockaif执行完就执行if lockb,当else lockb、else locka执行时就不会出现死锁可以执行下去。

因为线程是循环的所以总会有一次出现死锁,时间不同得到的代码长度也不同。

评分

参与人数 1技术分 +1 收起 理由
冯海霞 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 曹宇 于 2013-4-5 21:39 编辑

我自己想了想,突然发现,我机器的输出一直是这样,如图

一直都是线程0执行很久 然后线程1才抢到资源再执行很久。

我想如果想死锁,应该是现场0和1交替运行的时候,才有可能发生死锁把。
就是  线程0 进了A锁,还没进去B锁 Cpu去执行线程1了 然后线程1进去了B锁 然后去A锁进不去因为线程0在A锁中还没出,线程0想出 A锁就必须进去B锁然后再出B锁才能出A锁 但是因为线程1进去了B锁所以线程0根本进不去B锁 就谈不上出A锁了 所以 线程0 和1 都卡在那 谁也出不去 谁也进不去。

也就是 0想进B就要出A,就要等1出B  可是1 想出B就要进A 所以卡那了。
因为 locka  lockb 两个AB锁是静态共享的,所以两个线程共享两个锁,所以两个线程就都在那走不动了。

不知道我这样理解对不对,还望高手解答。
回复 使用道具 举报
田光峰 发表于 2013-4-5 21:35
while(true)
                        {
                                synchronized(MyLock.locka)

嗯,刚我查看了输出,突然想到的和你说的一样。

应该就是这样。因为我cpu处理太快。而且我看输出都是 一直是0线程运行 很久 然后1在抢到执行权再运行很久,所以0和1基本没有交替运行。既然没有交替运行,那么就应该不会出现死锁了。不会出现我出不去,它也出不去。
回复 使用道具 举报
以上要想发生死锁:
一种死锁可能情况:
①cpu切换到Thread-0进入 synchronized(MyLock.locka) 持有locka
②cpu切换到 Thread-1进入 synchronized(MyLock.lockb)持有lockb
③cpu再次切换到 Thread-0执行synchronized(MyLock.lockb) 需要持有lockb,才能进入->进不去
④cpu再次切换到 Threa-1 执行 synchronized(MyLock.locka) 需要持有locka,才能进入->进不去

但是可能发生一种很和谐的情况,就是你的运行结果:
①cpu切换到Thread-0 进入 synchronized(MyLock.locka) 持有locka,接着向下执行,当把同步代码块执行完,释放了locka和lockb
②cpu切换到Thread-1 同理.

我之前 手动模拟,减小死锁概率,也就是可以让其中一个线程sleep会,让cpu执行另一个线程,也就是上面的和谐情况.
   

评分

参与人数 1技术分 +1 收起 理由
冯海霞 + 1

查看全部评分

回复 使用道具 举报
张洪慊 发表于 2013-4-5 21:49
以上要想发生死锁:
一种死锁可能情况:
①cpu切换到Thread-0进入 synchronized(MyLock.locka) 持有locka

恩,我明白了。

我也想过用sleep(); 不过是想的让死锁发生,我给两个锁里都加上了sleep();想的能不能都睡一会再这一会CPU能去到别的线程玩,不过还是没发生死锁,可能CPU的处理方式不同吧。

不过原理我明白了,我相信要是一直运行下去总会锁住的,不过那个时间。

验证了一句话,多核CPU就是牛逼啊。
回复 使用道具 举报
曹宇 发表于 2013-4-5 23:50
恩,我明白了。

我也想过用sleep(); 不过是想的让死锁发生,我给两个锁里都加上了sleep();想的能不能都 ...

唉,这玩意就是拼人品O(∩_∩)O哈哈~
回复 使用道具 举报
既然明白了,记得改成【已解决】~  这次帮你改了~
回复 使用道具 举报
陈丽莉 发表于 2013-4-6 00:28
既然明白了,记得改成【已解决】~  这次帮你改了~

恩,下线的时候忘了改了
回复 使用道具 举报
死锁并不是一种错误,有些时候深知能达到和谐状态哦,当两个线程各自运行的时候刚好能获得自己要的资源,这个时候就能达到一种资源和谐,这个时候可能会正常运行,锁不住。你的现象是正常的
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马