3

我有这堂课:

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 关联的锁
4

2 回答 2

2

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

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

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

那么你就会陷入僵局。locks是在每个线程的基础上获取的。

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

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

于 2012-05-18T12:51:59.557 回答
2

#2将会发生。

可重入同步

回想一下,一个线程不能获得另一个线程拥有的锁。但是线程可以获取它已经拥有的锁。允许一个线程多次获取同一个锁可以实现重入同步。这描述了一种情况,同步代码直接或间接调用一个也包含同步代码的方法,并且两组代码都使用相同的锁。如果没有可重入同步,同步代码将不得不采取许多额外的预防措施来避免线程导致自身阻塞。

于 2012-05-18T12:54:43.210 回答