【问题标题】:How can a thread acquire lock on two objects simultaneously as in this case?在这种情况下,线程如何同时获得两个对象的锁?
【发布时间】:2014-04-22 10:40:40
【问题描述】:
public void method(Type1 inst1, Type2 inst2) {
  synchronized(inst1) {
    synchronized(inst2) {
      //do something now
    }
  }
}

从这段代码可以理解,线程一旦进入方法,先获取inst1的锁,然后再获取inst2的锁,不释放inst1的锁。我假设这两个对象都没有被其他线程锁定。

  1. 如果一个线程一次只能获得一个对象的锁并且只能 当当前对象上的锁被释放时拥有另一个锁,如何 这段代码是否有效,或者更确切地说,它是我认为我在某处看到的有效代码吗?
  2. 如果 Type1 和 Type2 相同呢?
  3. 如果我们使方法同步会发生什么,考虑到它驻留在 方法的参数类型以外的类?

【问题讨论】:

  • 理论上,一个线程可以持有的锁数量没有限制。使用synchronized 获得的锁是隐式可重入的,所以inst1inst2 引用同一个对象没有问题。我认为这是某种家庭作业(如果是的话,你应该这样标记它)。它试图让你思考的是死锁——如果线程 1 调用此方法并传递 objAobjB,然后线程 2 调用它同时传递 objBobjA
  • 这是一个常用于解释死锁的代码。同意。但是据我所知,我读过一些文本,一个线程一次只能锁定一个对象,并且不能在不释放的情况下获取不同对象的锁。这是我的疑问!
  • 如果每个线程一次只允许持有一个锁,就不会有死锁这样的事情。你要么误解了你阅读的内容,要么你阅读的内容是错误的。仅仅因为有人在博客、论文甚至一本书中写了它,并不能使断言成立。
  • 如果一个线程可以一个一个地锁定许多不同的对象而不释放任何对象,那么我认为它肯定可以多次锁定同一个对象。那么为什么会有一个可重入锁定的概念,它被解释为一些大的子主题?我这里只说一个线程,我理解在多个线程的情况下,如果一个线程试图获取一个已经被另一个线程占用的对象的锁,可能会出现死锁情况。

标签: java multithreading synchronization thread-synchronization


【解决方案1】:

1 .如果一个线程一次只能获得一个对象上的锁,并且在当前对象上的锁被释放时只能拥有另一个锁,那么这段代码怎么能有效,或者更确切地说,它是我认为我见过的有效代码什么地方?

这是一个有效的代码,锁不在方法所在的对象上,而是在inst1inst2上。另外,锁不在类上,而是在每个对象上

2 。如果 Type1 和 Type2 相同呢?

同样,锁在对象上,而不是在类上。如果inst1和inst2相同,那么线程只有一个锁,同一个线程“重新入锁”是有效的

3 .如果我们让方法同步,考虑到它驻留在方法的参数类型以外的类中,会发生什么?

那么你还有另一个锁,这次是在执行方法的对象(而不是类)上。

【讨论】:

  • 一个线程可以同时锁定多个对象吗?
  • @xploreraj 从嵌套同步块中可以看出它同时锁定了 inst1 和 inst2。
【解决方案2】:

感谢@morgano@Nick Holt,我了解到一个线程可以同时持有多个锁(不同的对象) ,或多次在同一个对象上(使用synchronized 获得的锁是隐式可重入的)。

【讨论】:

    【解决方案3】:

    如果您每次需要以相同的顺序获取这两个对象的锁定,您的代码没有问题。

    例如,如果你有两个方法

    public void methodA(Type1 inst1, Type2 inst2) {
      synchronized(inst1) {
        synchronized(inst2) {
          //do something now
        }
      }
    }
    
    public void methodB(Type1 inst1, Type2 inst2) {
      //wrong
      synchronized(inst2) {
        synchronized(inst1) {
          //do something now
        }
      }
    }
    

    你有一个潜在的死锁问题,因为一个线程可以获得 inst1 上的锁并等待 inst2 的锁,而另一个线程拥有 inst2 上的锁并等待 inst1 上的锁。

    【讨论】:

    • 好的,但这不是我的疑问!我怀疑线程如何同时锁定两个对象。
    【解决方案4】:

    该代码很可能会导致死锁雷区,这是肯定的。

    锁定inst2的第二个线程(threa2)不一定要通过methodA运行,但可能会在另一个过程中锁定对象inst2,并且在methodA中的thread1之前这样做,然后访问方法A并尝试锁定inst2 , 在发布 inst2 之前。啊啊啊!嘘! :(。

    建议的解决方案:
    在 methodA 上同步,而不是在 objects 上同步,因为这将锁定在 methodA() 中访问的所有资源 像这样

    public synchronized void methodA () {....}

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-16
      • 2015-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-01
      相关资源
      最近更新 更多