【问题标题】:Does deadlock happen per method or per class?每个方法或每个类都会发生死锁吗?
【发布时间】:2013-12-19 10:38:56
【问题描述】:

想象一下,我的 Class First 有几个同步方法。当线程锁定类First 时,它是按方法锁定还是按类锁定?比如下面的代码会发生死锁吗?

public class DeadLockQuestion {

    public static class First{
        public synchronized void a(){

        }
        public synchronized void b(){

        }
        public synchronized void c(){

        }   
        public synchronized void d(){

        }
        public synchronized void e(){

        }       
    }

    public static void main(String... args){
        First f = new First();

        //This code is run in Thread 1
        f.a();
        // End
        //This code is run in Thread 2 simultanously
        f.b();
        //End
        // We have also Threads 3 & 4 & 5 that invoke c,d and e simultanously

    }

}

【问题讨论】:

  • 每个资源都会发生死锁。现在你说!
  • 那么这种情况下resource对应的是什么?

标签: java multithreading deadlock


【解决方案1】:

Java 中有两个锁。一是对象锁。另一个是类锁。 对象锁只锁定对同步的非静态函数的访问。和类锁只锁定同步的静态函数。 对你来说,它是对象f 上的对象锁定。因此,所有同步的非静态函数都为对象f 锁定。 由于所有线程都使用同一个对象f,因此一次只有一个线程能够访问您的非静态函数a(), b(),...。 阅读更多here

does deadlock happen for the following code?

不,在您的情况下不会发生这种情况。因为当一个Thread 持有锁时,其他线程无法进入您的同步函数。DeadLock happens due to resources.
您只有一个资源,即 Object f。这里没有死锁的意义,因为 First 类不会锁定另一个对象 并且不会发生循环锁定。死锁需要循环锁

一些信息:

  1. java 中的同步保证没有两个线程可以执行一个 同时需要相同锁的同步方法或 同时。
  2. synchronized 关键字只能用于方法和代码块。 这些方法或块可以是静态的或非静态的。
  3. 当一个线程进入java同步方法或阻塞它时 获得一个锁,并且每当它离开java同步方法或 阻止它释放锁。即使线程离开也会释放锁 完成后或由于任何错误或 例外。
  4. 静态同步和非静态都可能 同步方法可以同时或并发运行,因为 他们锁定不同的对象。
    有用的来源Herehere

【讨论】:

  • 那么,如果我希望能够通过方法锁定 f 而我无法使 f 方法成为静态,我该怎么办?而且反正有这样的结构不会导致死锁?
  • @Johnny 我不明白你的问题。你能解释一下吗?
  • 你可以这样做public synchronized void a(){ synchronized(DeadLockQuestion .class){//code here} }。这是你的意思吗?
  • 我认为 Tim B 已经给出了这个评论的答案。应该是他所说的'public void a(){ synchronized(object){//code goes here}}'
  • 请通过this 一次。这会很有帮助。因为 Tim B 也锁定了objects,它与Class Level Locking 不同。 :)
【解决方案2】:

死锁发生在线程,而不是方法或类。

死锁线程也持有锁,但在这种情况下,无法分辨出哪些锁,因为您没有演示实际的死锁场景(如果两个线程调用f的同步方法,一个通过,另一个等待;死锁至少需要两把锁)。

【讨论】:

    【解决方案3】:

    要独立锁定每个方法,请在每个方法中使用同步块并锁定不同的对象。

    如果你在类中已经有一个合适的(并且它应该是 final 以防止潜在的问题)对象,你可以使用它。如果没有创建一个private final Object aLock = new Object(); 然后锁定它,例如:

    private final Object aLock = new Object();
    
    public void a() {
        synchronized(aLock) {
             // Do stuff that needs the lock
        }
        // do stuff that doesn't need the lock
    }
    

    只要您需要,请始终保持锁定,但不再需要。

    【讨论】:

      【解决方案4】:

      a() 是同步方法时,f.a() 字面意思是:

      synchronized(f){
          f.a();
      }
      

      所以在这种情况下,对象监视器f 会发生锁定。在您的情况下,您需要第二个对象来创建死锁,我认为不可能使用单个对象监视器创建死锁。一个典型的死锁模式是当锁获取的顺序没有被维护时,即当这发生在两个不同的线程中时:

      synchronized(a){
           synchronized(b){
               ...
           }
      }
      // and
      synchronized(b){
           synchronized(a){
               ...
           }
      }
      

      【讨论】:

        【解决方案5】:

        首先,线程会发生死锁,而不是类或方法。

        当存在锁的循环依赖时会发生死锁。

        Thread A ---> locks L1        ---> tries to lock L2
        
             Thread B ----> locks L2                         ------> tries to lock L1
        

        Image source: FusionReactor deadlock plugin

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多