java - 如果一个线程试图获取它已经持有的锁会发生什么?

标签 java multithreading concurrency

这是取自约书亚·布洛赫 (Joshua Bloch) 所写的一本书。
我不是以英语为母语的人,因此有理由要求澄清疑问。

Because intrinsic locks are reentrant, if a thread tries to acquire a lock that it already holds, the request succeeds. Reentrancy means that locks are acquired on a per-thread rather than **per-invocation basis.


通过每次调用,他是否意味着每个方法调用?
考虑一下片段:
class Factoriser {  
    public synchronized void doSomething(){
       // code goes here
    }
}
假设有一个 Thread A并且能够获得具有实例方法doSomething()的对象的锁定.由于某种原因,同一线程 Thread A再次获得对同一对象实例方法的锁定 doSomething() (也想象一下之前的锁还没有被释放)。
如果我正确理解了 Joshua 的陈述,那么即使有 2 个方法调用/调用,也只有一个锁。我的理解是否正确。请详细说明。作者在下面的段落中澄清了这一点,这进一步使我感到困惑。

Reentrancy is implemented by associating with each lock an acquisition count and an owning thread. When the count is zero, the lock is considered unheld. When a thread acquires a previously unheld lock, the JVM records the owner and sets the acquisition count to one. If that same thread acquires the lock again, the count is incremented, and when the owning thread exits the synchronized block, the count is decremented. When the count reaches zero, the lock is released.


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

最佳答案

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

// 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 步我们将释放锁,这将是一个错误,因为我们仍在外部同步块(synchronized block)中。因此,需要计数器来正确实现重入。

关于java - 如果一个线程试图获取它已经持有的锁会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38678305/

相关文章:

java - 在 Java 中嵌套 CompletionStages 以使内部 block 在外部 block 之前运行

应用 java AtomicIntegeraccumulateAndGet

java - GWT 解析不同语言环境中的日期

java - Java 类加载器如何在 "regular"情况下工作(类加载器的非显式使用)

javascript - 工作人员在 Chrome 中阻塞 UI 线程

c++ - 测试对象是否未被删除

java - 无法将字符串转换为 int (Java)

java - Spring 存储库下载错误 servlet-api.jar 的问题

mysql - MySQL 中简单和复杂存储过程的线程安全

asp.net - 只读 session 可写