当前位置: 首页 > 知识库问答 >
问题:

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

滕星纬
2023-03-14

这是取自约书亚·布洛赫(Joshua Bloch)写的一本书。

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

因为内部锁是可重入的,所以如果线程试图获取它已经持有的锁,那么请求就会成功。重传意味着锁是按线程获取的,而不是按调用**获取的。

根据每次调用,他是指每次方法调用吗?考虑片段:

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

假设有一个线程A,并且能够获取具有实例方法do

如果我正确理解了约书亚的陈述,那么即使有 2 个方法调用/调用,也只有一个锁。我的理解正确吗?请详细说明。作者在下面的段落中澄清了这一点,这进一步使我感到困惑。

通过将每个锁与一个获取计数和一个拥有线程相关联来实现可重入性。当计数为< code >零时,锁被认为是未锁定的。当一个线程获得一个先前未被锁定的锁时,JVM会记录拥有者,并将获取计数设置为1。如果同一个线程再次获得锁,计数器就增加,当拥有线程退出同步块时,计数器就减少。当计数达到零时,锁被释放。

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

共有1个答案

匡翰
2023-03-14

计数器用于匹配锁获取和粪便。仅当计数器为 0 时,才能释放锁。将方法 foo() 标记为同步并在对象 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步我们将释放锁,这将是一个错误,因为我们仍然在外部同步块中。因此,需要计数器来正确地实现重入。

 类似资料:
  • 问题内容: 线程都是可运行的,并且它们拥有相同的锁。两个线程都可以运行时,它们可以锁定相同的地址吗?那是JRE错误吗? 问题答案: 该问题仅存在于线程转储中。实际上,在任何时间点,锁都仅由一个线程持有。但是,线程转储显示两个具有相同锁的不同线程,因为它不是原子的。 可以使用以下程序轻松重现该行为:

  • 在实践中考虑java并发的片段 同一本书的摘录- 考虑易失性变量的一个好方法是想象它们的行为大致类似于上面清单中的同步整数类,用调用get和set来替换易失性变量的读写。然而,访问易失性变量不执行锁定,因此不会导致执行线程阻塞,这使得易失性变量成为比同步更轻量级的同步机制。 线程限制的一种特殊情况适用于可变变量。对共享的易失性变量执行读-修改-写操作是安全的,只要确保该易失性变量仅从单个线程写入。

  • 假设cpu读取一个截断整数的字。我已经读到,如果没有启用结构填充,CPU将不得不进行两次读取:它必须先读取前半部分,然后分别读取后半部分,然后将它们重新组合在一起进行计算。 cpu如何注意到整数(例如)已被截断?

  • 问题内容: 在具有并发访问的程序中使用映射时,是否需要在函数中使用互斥体来 读取 值? 问题答案: 读者众多,没有作家可以: https://groups.google.com/d/msg/golang- nuts/HpLWnGTp-n8/hyUYmnWJqiQJ 一个作家,没有读者是可以的。(否则,地图不会太好。) 否则,如果至少有一个作家,而作家或读者至少还有一个,那么 所有 读者 和 作家都

  • 我对高级Java和可重入锁的学习相当陌生。我知道ReentrantLock有一个公平性参数,它确保将锁提供给最缺线程(与同步的内部锁不同) 但是,Reentrant也意味着同一线程可以通过递增holdcount来一次又一次地重新获取锁。如果同一个线程一直获得锁,它如何保证公平性?

  • 问题内容: 我有一个LockManager来管理多个线程的锁。有时线程是坏男孩,我必须杀死它们并要求LockManager释放所有锁。但是,由于我无法在Java中使用ReentrantLock,因此无法解锁另一个线程拥有的锁。 我被迫使用锁(不能使用信号灯,这是作业的重点)。是否有任何Java Lock实现可让我解锁其他线程拥有的锁? 到目前为止,我考虑的选项是: 以允许我执行此操作的方式重新实现