使用相同的锁从另一个同步块调用同步块

时间:2012-05-18 12:50:03

标签: java multithreading deadlock

我有这堂课:

public class MyClass {

    public MyClass(){}

    public void actionA(){
        synchronized(MyClass.class){
            System.out.print("A");
        }
    }

    public void actionB(){
        synchronized(MyClass.class){
            actionA();
        }
    }

}

哪一个(如果有的话)是真的?

  1. 调用actionB()会导致死锁,因为actionA()永远无法获取与MyClass.class相关联的锁
  2. 调用actionB()不会导致死锁,因为它已经获取了与MyClass.class相关联的锁

2 个答案:

答案 0 :(得分:2)

#2将会发生,因为调用线程具有锁定。

但是,如果代码看起来像这样:

public void actionB(){
    synchronized(MyClass.class) {
      Thread thread = new Thread(new Runnable { run() { actionA(); }});
      thread.start();
      thread.join();
    }
}

然后你会陷入僵局。 locks是基于每个线程获取的。

我发现一个有用的心理图片是挂锁的共享密钥。一次只有一个线程可以拥有该密钥,但显然相同的密钥将打开它适合的任何锁(该密钥适合使用相同同步对象的任何锁)。

顺便说一句,在任何公开可见字段上进行同步都是不好的做法,因为远程删除的另一段代码可能会锁定同一个对象,从而导致不必要的争用并可能出现死锁。

答案 1 :(得分:2)

#2将会发生。

Reentrant Synchronization

  

回想一下,线程无法获取另一个线程拥有的锁。   但是一个线程可以获得它已经拥有的锁。允许一个   线程多次获取相同的锁启用重入   同步。这描述了同步代码的情况,   直接或间接调用也包含的方法   同步代码,两组代码使用相同的锁。没有   可重入同步,同步代码将需要很多   另外的预防措施,以避免线程导致自己阻止。