【问题标题】:What happens if a thread tries to acquire a lock that it already holds?如果一个线程试图获取它已经持有的锁会发生什么?
【发布时间】:2016-07-30 20:41:29
【问题描述】:

这摘自 Joshua Bloch 的一本书。

我不是以英语为母语的人,因此有理由要求澄清疑问。

因为内在锁是可重入的,如果一个线程尝试 要获取它已经持有的锁,请求 成功。可重入意味着锁是在一个 每个线程而不是**每个调用的基础。

按每次调用,他是指按方法调用吗? 考虑 sn-p:

class Factoriser {  
    public synchronized void doSomething(){
       // code goes here
    }
}

假设有一个Thread A 并且能够获得具有实例方法doSomething() 的对象的锁定。由于某种原因,同一线程Thread A 再次获得了同一对象实例方法doSomething() 上的锁(也可以想象之前的锁尚未释放)。

如果我正确理解了 Joshua 的陈述,那么即使有 2 次方法调用/调用,也只会有一个锁。我的理解是否正确。请详细说明。作者在下面的段落中澄清了这一点,这让我更加困惑。

可重入是通过将每个锁与一个获取计数和一个拥有线程相关联来实现的。当计数为zero 时,该锁被视为未持有。当一个线程获得一个以前未持有的锁时,JVM 记录所有者 并将采集计数设置为 1。如果同一个线程 再次获得锁,计数增加,并且 当拥有线程退出同步块时, 计数递减。当计数为零时,锁被释放。

如果 Reentrancy/locks 获取不是基于每次调用,为什么 JVM 完成的计数设置为 2 对于我上面描述的场景?

【问题讨论】:

  • 那是 很多 bold。事实上,有这么多大胆变得毫无意义分心
  • 每个对象只有一个锁。任何数量的调用都只需要相同的锁(成功)。当最后一个锁被释放时,对象不再被锁定。为什么这么难?
  • @Andreas:谢谢。已删除。
  • 递归场景需要计数。

标签: java multithreading concurrency


【解决方案1】:

计数器用于匹配锁的获取和丢弃。只有当计数器为0时才能释放锁。将方法foo()标记为synchronized并在对象obj上调用它与以下块相同:

// calling obj.foo()
synchronized(obj) {
    // Do the foo-work
}

假设我们有两个同步方法:foo()bar(),后者是从前者调用的。调用将具有以下结构:

final FooBar obj = new FooBar();

// calling obj.foo()
synchronized(obj) { // 1. here the lock is acquired, the counter is set to 1

    // do some foo-work

    // calling obj.bar()
    synchronized(obj) {  // 2. the same lock object, the counter is set to 2
        // do the bar-work
    } // 3. the counter is set to 1, the lock is still not released

    // continue doing the foo-work
} // 4. the counter is 0, the lock is released

如果没有计数器,在第 3 步我们将释放锁,这将是一个错误,因为我们仍在外部同步块中。因此,需要计数器来正确实现重入。

【讨论】:

  • 整个对象都被锁定了吗?或者只有那些标记为该对象同步的方法。
  • 我不确定我是否完全理解您的问题。所有同步方法都使用相同的锁定对象——调用这些方法的对象(静态同步方法使用Class 对象)。所以,你可以说整个对象都被锁定了。但是,无论活动锁如何,仍然可以调用未标记为同步的方法。只需将每个同步方法视为非同步方法,而是放在一个块中,该块在调用此方法的对象上同步,正如我在回答中所展示的那样,许多事情会更容易理解。
  • 方法本身不被锁定很重要。它们只能针对已经在某个线程中调用并且仍在工作的特定对象(或静态类)被“锁定”。同时,另一个线程可以在另一个对象上调用相同的方法,并且不会被阻塞,因为它会使用另一个对象进行锁定。因此,锁定的是对象,而不是方法。但是这些锁只影响使用相同对象的同步方法和同步块。
猜你喜欢
  • 2018-04-25
  • 2021-09-02
  • 1970-01-01
  • 2015-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-12
  • 1970-01-01
相关资源
最近更新 更多