黑马程序员技术交流社区

标题: 关于死锁的一些疑问 [打印本页]

作者: 曹宇    时间: 2013-4-5 21:10
标题: 关于死锁的一些疑问
本帖最后由 曹宇 于 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. }
复制代码

作者: 朱盛文    时间: 2013-4-5 21:32
其实死锁并不是一种错误的代码,在运行和编译时期也都不会报错。在程序中加同步锁是为了解决安全隐患,即当程序运行到某段加同步锁的代码时,只允许一个线程进行访问,待此线程运行完这段代码并释放锁的时候,下一个线程才能拿到锁并运行此段代码。
而死锁是在用嵌套锁时,由于多线程同时进行,而互相抢到了对方的锁,使得双方都无法运行下去,而使程序处于阻塞状态。
就如毕老师举的例子:两个人去吃面,但是只有一双筷子,起初每人拿着一只筷子,然后你借给我一只,我就先吃一口;然后我又借给你一只,你也就吃一口……这样按部就班的来,大家就都能吃到面;但是如果双方都抢着吃,协商不下来,谁都不放自己手中的筷子,那谁都吃不了面。
作者: 我手心里的宝    时间: 2013-4-5 21:33
死锁,锁住的时间理论是同一时间锁住,但是争夺cpu的访问,cpu访问时随机的
而且现在的电脑是双核的了,现在的都是4核的,所以
它说不定在什么时候锁住,这个事随机的,所以,不用纠结
作者: 田光峰    时间: 2013-4-5 21:35
  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执行时就不会出现死锁可以执行下去。

因为线程是循环的所以总会有一次出现死锁,时间不同得到的代码长度也不同。
作者: 曹宇    时间: 2013-4-5 21:36
本帖最后由 曹宇 于 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:41
田光峰 发表于 2013-4-5 21:35
while(true)
                        {
                                synchronized(MyLock.locka)

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

应该就是这样。因为我cpu处理太快。而且我看输出都是 一直是0线程运行 很久 然后1在抢到执行权再运行很久,所以0和1基本没有交替运行。既然没有交替运行,那么就应该不会出现死锁了。不会出现我出不去,它也出不去。
作者: 张洪慊    时间: 2013-4-5 21:49
以上要想发生死锁:
一种死锁可能情况:
①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执行另一个线程,也就是上面的和谐情况.
   
作者: 曹宇    时间: 2013-4-5 23:50
张洪慊 发表于 2013-4-5 21:49
以上要想发生死锁:
一种死锁可能情况:
①cpu切换到Thread-0进入 synchronized(MyLock.locka) 持有locka

恩,我明白了。

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

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

验证了一句话,多核CPU就是牛逼啊。
作者: 张洪慊    时间: 2013-4-6 00:06
曹宇 发表于 2013-4-5 23:50
恩,我明白了。

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

唉,这玩意就是拼人品O(∩_∩)O哈哈~
作者: 陈丽莉    时间: 2013-4-6 00:28
既然明白了,记得改成【已解决】~  这次帮你改了~
作者: 曹宇    时间: 2013-4-6 13:06
陈丽莉 发表于 2013-4-6 00:28
既然明白了,记得改成【已解决】~  这次帮你改了~

恩,下线的时候忘了改了
作者: 何清林    时间: 2014-2-23 15:32
死锁并不是一种错误,有些时候深知能达到和谐状态哦,当两个线程各自运行的时候刚好能获得自己要的资源,这个时候就能达到一种资源和谐,这个时候可能会正常运行,锁不住。你的现象是正常的




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