2013-11-03 127 views
2

我正在尝试Java多线程中的死锁概念。我碰到一个代码段这有可能导致死锁传来:当我运行它时,为什么这个代码永远不会死锁?

public class Deadlock { 
double amount = 10.0; 

public double deposit(double d) { 
    amount += d; 
    return amount; 
} 

public double withdraw(double d) { 
    amount -= d; 
    return amount; 
} 

public static void transfer(Deadlock from, Deadlock to,double d) { 
    synchronized(from) { 
     synchronized(to) { 
      from.withdraw(d); 
      try { 
       System.out.println(Thread.currentThread().getName()); 
       Thread.sleep(5000); 
      }catch(Exception e){} 

      to.deposit(d); 
      System.out.println("Done"); 
     } 
    } 
} 

public static void main(String[] args) { 
    final Deadlock a = new Deadlock(); 
    final Deadlock b = new Deadlock(); 

    Thread t1 = new Thread(new Runnable() { 
     public void run() { 
      transfer(a, b, 10.0); 
     } 
    }); 
    t1.start(); 



    Thread t2 = new Thread(new Runnable() { 
     public void run() { 
      transfer(b, a, 10.0); 
     } 
    }); 
    t2.start(); 
} 
} 

基本上,代码试图在同一时间获得关于对象A和B的锁。但是,当我运行它时,代码总是成功完成。为什么不是这个僵局?

+0

它并不会因为运气好而死锁。 (在这种情况下,你可能很幸运,因为你正在快速连续获取锁具。) –

回答

4

为了要发生的僵局,就需要有一些以下情形发生:

t1 acquires lock a 
t2 acquires lock b 

t1 attempts to acquire lock b 
t2 attempts to acquire lock a 

你可以强制使用?您可以尝试在锁定采集之间移动睡眠声明,但这一切都必须发生在并非真正处于您的直接控制之下的窗口内。

试试这个:

public static void transfer(DeadLock from, DeadLock to,double d) { 
    synchronized(from) { 
     try { 
      System.out.println(Thread.currentThread().getName() +" acquires lock " +from); 
      Thread.sleep(5000); 
      synchronized(to) { 
       System.out.println(Thread.currentThread().getName() +" acquires lock " +to); 
       from.withdraw(d); 
       to.deposit(d); 
       System.out.println("Done"); 
      } 
     }catch(Exception e){} 
    } 
} 

,并确认你陷入僵局的时候,发送SIGQUIT信号到你的Java进程 - JVM将死锁

+0

谢谢!这工作。 – codewarrior

0

sleeping a Thread does not release the locks it holds, while waiting releases the lock

T1拥有两个僵局对象的锁,即使在睡觉,只有当T1存在了相应的同步锁,T2获得对它的访问。

因此,要引入死锁,您需要在同步语句之间进行睡眠。

也或者你可以尝试,而不是Thread.sleep(5000);to.wait(5000);

4

它只是到线程调度,如果一个线程能够达到这两个

synchronized(from) { 
    synchronized(to) { 

其他线程到达第一前。添加一个足够大的sleep这些之间

synchronized (from) { 
    try { 
     Thread.sleep(20L); 
    } catch (InterruptedException e1) { 
     e1.printStackTrace(); 
    } 
    synchronized (to) { 

并且您应该遇到死锁。

2

第一线到达报告线程方法转移将获得这两个资源(来回地)以至于它可能不会与第二线程交错。话虽如此,这段代码仍然容易发生死锁。下面的代码尝试获取第一个锁的时间足够长,以便第二个线程运行:

public static void transfer(Deadlock from, Deadlock to, double d) throws InterruptedException { 
    synchronized (from) { 
     Thread.sleep(5000); 
     synchronized (to) { 
      from.withdraw(d); 
      System.out.println(Thread.currentThread().getName()); 
      to.deposit(d); 
      System.out.println("Done"); 
     } 
    } 
} 
相关问题