为什么这不会导致死锁

为什么这不会导致死锁

问题描述:

为什么下面这段代码不会导致死锁?为什么这不会导致死锁

从我有限的多线程编程的理解,当getBar1()叫,sharedBuffer将被“锁定”,因此,当方法试图调用getBar2(),该线程将不得不等待sharedBuffer(由其自身持有!)。换句话说,getBar2()不能返回,直到getBar1()有(并且发布sharedBuffer)。但另一方面,getBar1()无法返回,因为它正在等待getBar2()返回。

==>死锁。 (但实际上,它不是,这就是为什么我很困惑)

... 
Foo sharedBuffer = new Foo(); 

Bar1 getBar1() 
{ 
    Bar1 bar1; 
    synchronized (sharedBuffer) 
    { 
      bar1 = sharedBuffer.getBar1(); 
      if (bar1 == null) 
       bar1 = new Bar1(sharedBuffer, getBat2()); 
      sharedBuffer.setBar1(bar1); 
    } 
    return bar1; 
} 

Bar2 getBar2() 
{ 
    Bar2 bar2; 
    synchronized (sharedBuffer) 
    { 
     bar2 = sharedBuffer.getBar2(); 
     if (bar2 == null) 
      bar2 = new Bar2(); 
    } 
    return bar2; 
} 
... 
+0

阅读有关重入锁的信息。那些在Java中是本地的是。 – 2013-03-15 16:44:33

Java的显示器是递归的,这意味着同一个线程可以获取同样的锁几次。

从JLS(§17.1 Synchronization):

线程t可以锁定特定的监视器多次;每次解锁都会反转一次锁定操作的效果。

+0

啊,所以'getBar1()'访问'sharedBuffer'并不会阻止它调用'getBar2()',它也会访问'sharedBuffer'? – 2013-03-15 16:46:13

+0

@OneTwoThree:的确如此。 – NPE 2013-03-15 16:48:24

+0

但是,如果其他线程试图调用'getBar2()',它会阻塞,直到这个完成? – 2013-03-15 16:52:00

当并发操作尝试以不同顺序锁定两个或多个资源时,会发生死锁,并且它们都等待资源被另一个锁定。

  • T1同步于R1:

    例如,线程T1和T2上的资源R1和R2同步。

  • 调度程序决定T2应运行
  • T2在R2上同步。
  • T2尝试在R1上同步;它*等到T1放弃锁定。
  • 调度器看到该T2不能继续运行,所以允许T1运行
  • T1试图在同步R2;它*等到T2放弃锁定。
  • 两个线程可以继续

你在做什么这里是基本同步的,只允许一个对象在同一时间访问sharedBuffer

它没有死锁,因为你真的只有一个锁。在这两个函数中,您都锁定在sharedBuffer上。当第一个线程调用getBar1()时,它锁定在sharedBuffer上。当同一个线程调用getBar2()时,它会碰到synchronized块并且已经拥有锁,所以它只是进入锁。

如果您想引起死锁,请使用两个不同的值来锁定。然后,如果时间顺序正确,你只能看到它。如果你想强制一个死锁,确保第一个线程休眠足够长的时间,以便第二个线程获得一个锁。

这里有一些代码会死锁...(未经测试,prolly有错别字)。这应该起作用,因为不同的线程拥有的锁比想要锁的锁要好。

public class Deadlock extends Thread 
{ 
    private Deadlock other; 
    private String name; 

    public static void main(String[] args) 
    { 
     Deadlock one = new Deadlock("one"); 
     Deadlock two = new Deadlock("two"); 
     one.setOther(two); 
     two.setOther(one); 
     one.start(); 
     two.start(); 
    } 

    public setOther(Deadlock other){ this.other = other; } 

    public void run() { 
     deadlock(); 
    } 

    public synchronized deadlock() { 
     System.out.println("thread " + this.name + " entering this.deadlock()"); 
     sleep(1000); // adjust as needed to guarantee deadlock 
     System.out.println("thread " + this.name + " calling other.deadlock()"); 
     other.deadlock(this.name); 
     System.out.println(name + " - deadlock avoided!"); 
    } 
}