黑马程序员技术交流社区

标题: 继续问 这个为什么锁不上 死锁问题 为什么不能发现死锁 给我 [打印本页]

作者: 付鹏    时间: 2012-3-18 00:49
标题: 继续问 这个为什么锁不上 死锁问题 为什么不能发现死锁 给我
public class DidSynchronized {
        public static void main(String[] args) {
                Thread a = new Thread(new xiancheng(true));
                Thread b = new Thread(new xiancheng(false));
                a.start();
                b.start();
        }        
}

class xiancheng implements Runnable {
        private boolean flag;
        Object obj1 = new Object();
        Object obj2 = new Object();

        xiancheng(boolean flag) {
                this.flag = flag;
        }
        public void run() {
                if(flag) {
                        while(true){
                                synchronized(obj1) {
                                                System.out.println("if-----obj1");
                                                synchronized(obj2) {
                                                        System.out.println("if-----obj2");
                                                }
                                }
                        }
                }
                else {
                        while(true){
                                synchronized(obj2) {
                                        System.out.println("-----obj2");
                                        synchronized(obj1) {
                                                System.out.println("else-----obj1");
                                        }
                                }
                        }
                }
        }
}


         
为什么这两个锁不上 别告诉我怎么改 我知道怎么改 我就想知道为什么?
作者: 贠(yun)靖    时间: 2012-3-18 00:54
大哥 你new了两个 Object的对象  这是两个锁  不是一个锁~~~!  死锁必须是同一个锁
  你拿两把锁  两个线程    一个线程持有一把锁 怎么死锁呢?
作者: 付鹏    时间: 2012-3-18 00:55
贠(yun)靖 发表于 2012-3-18 00:54
大哥 你new了两个 Object的对象  这是两个锁  不是一个锁~~~!  死锁必须是同一个锁
  你拿两把锁  两个线 ...

是两个对象  ===   那   static Object obj1 = new Object();
                                   static  Object obj2 = new Object();
这就是创建一个了?

作者: 贠(yun)靖    时间: 2012-3-18 00:59
付鹏 发表于 2012-3-18 00:55
是两个对象  ===   那   static Object obj1 = new Object();
                                   stati ...

是的,要么你就创建一个锁  要么就搞两个static的锁 才能搞成死锁的
作者: 梁锡伟    时间: 2012-3-18 01:00
  Thread a = new Thread(new xiancheng(true));
   Thread b = new Thread(new xiancheng(false));

每new一个线程就有1个obj1和obj2,一共四个,懂?

作者: 彭盼    时间: 2012-3-18 01:27
Object obj1 = new Object();
Object obj2 = new Object();

这两个都要在前面加上"static"关键词,具体原因我找了些资料,附上一个类似的实例及分析,希望共同提高:
死锁的必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。            
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。            
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

obj1和obj2是模仿2个资源,这个只要是个静态共享对象都可以
一个线程通过synchronized 锁定自己的资源obj1,
并且需要在后面的过程争取第二个资源obj2,
而第二个线程同理锁定自己的obj2,
然后在后面过程争取第一个资源
因为不剥夺条件,不释放自己,又形成循环争取对方资源的环,
从而形成死锁,不加静态修饰时,主函数执行后,遇到建立对象的代码,就会
创建多个锁对象的副本,所以程序在执行时不会锁上,网上找了个类似例子,你看看:

package com.jk.deadLock;

public class DeadLock implements Runnable{
   static Object obj1 = new Object();
   static Object obj2 = new Object();
  int flag = 1;

public void run(){
  System.out.println(flag);
  if(flag == 1)
  {
   synchronized(obj1){
    try {
     Thread.sleep(1000);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    synchronized(obj2)
    {
     System.out.println("my name is t1");
    }
   }
  }
   if(flag == 2)
  {
   synchronized(obj2){
    try {
     Thread.sleep(1000);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    synchronized(obj1)
    {
     System.out.println("my name is t2");
    }
   }
  }
}

public static void main(String[] args) {
  DeadLock d1 = new DeadLock();
  DeadLock d2 = new DeadLock();
  d1.flag = 1;
  d2.flag = 2;
  Thread t1 = new Thread(d1);
  Thread t2 = new Thread(d2);
  t1.start();
  t2.start();
  
}

这里如果不为static,当然就创建了多个副本啊。
因为如果不为static,当执行完以下两行时:
DeadLock d1 = new DeadLock();
DeadLock d2 = new DeadLock();
内存里会有d1、d2两个DeadLock对象,每个DeadLock对象中会有obj1、obj2两个Object,这点很重要!即内存中对象如下:
d1:{obj1,obj2,flag}
d2:{obj1,obj2,flag}
设置完flag以后,变成:
d1:{obj1,obj2,flag==1}
d2:{obj1,obj2,flag==2}
现在,进行t1.start()的时候,会相继锁d1.obj1,再锁d1.obj2最后System.out.println("my name is t1");进行t2.start()的时候,会相继锁t2.obj1,再锁t2.obj2最后System.out.println("my name is t2")。所以完全不会存在死锁的问题。

而当两个Object为static 时,内存对象将会是
d1:{flag==1}
d2:{flag==2}
{obj1,obj2}
此时,再运行 t1.start();  t2.start();时,obj1和obj2会分别被两个d锁住,从而引发死锁。





作者: 唐巍    时间: 2012-3-18 03:45
你这里同步代码块中嵌套了同步代码块,而两个同步代码块用了不同的锁,会造成死锁,导致程序卡死。所以才会锁不上。这样说懂了吗?




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