【问题标题】:how does locking a reentrant lock again helps when we already have the lock on it? [duplicate]当我们已经拥有锁时,再次锁定可重入锁有什么帮助? [复制]
【发布时间】:2018-08-30 12:58:50
【问题描述】:

因此,如果当前线程再次获得锁,则可重入锁将计数加一。我无法理解的是为什么以及如何帮助或使我们受益?

【问题讨论】:

  • 欢迎来到 StackOverflow!看起来您的问题实际上与 Java 无关,因为可重入锁是一个远远超出单一语言的概念。在此基础上,它可能已经有了答案here
  • JavaDoc for ReentrantLock 也给出了一些解释。
  • 根据 JavaDoc(参见我上面的评论),ReentrantLock 确实具有“与使用同步方法和语句访问的隐式监视器锁相同的基本行为和语义”这是一个简单的example,使用关键字synchronized 来查看重入。

标签: java locking java.util.concurrent reentrantlock


【解决方案1】:

重入锁这样做的原因是不再锁定已经获得该锁的同一个线程。

例如:假设您有线程 A 正在获取您的可重入锁 A。线程 B 尝试获取锁 A,这将导致线程 B 被阻塞(有关线程状态的更多信息可以找到 here )。现在,线程 A 正在尝试(再次)获取 Lock A。

因为可重入锁现在增加了它的计数,线程 A 没有被阻塞。线程 A 仍然可以访问锁并且可以继续(锁存储有关深度的信息)。如果他(迟早)释放了锁,计数将再次降低,以检查线程 A 是否仍然需要锁。如果计数为 0,意味着线程 A 每次获得都释放,线程 B 将通过锁获得访问权。

如果没有重入,您现在将拥有一个deadlock。为什么?因为线程 A 有锁并且会等待再次获得它。


并发可能非常复杂,reentrancy 有助于(只是一点点)降低这种复杂性。

【讨论】:

  • 这造成了一些相当具有误导性的逻辑飞跃,并且只是简单/偶然地提到了基于计数器的锁定解决的真正问题。
  • @MarkAdelsberger 我提供了一个示例,该示例通过一个示例的源代码也可以查找。为什么我只是简单地/顺便提一下真正的问题?问题不是关于“什么是死锁”,而是关于为什么需要计数器。
  • 计数器无法解决死锁。它解决了锁的过早释放。这就是我的观点。
  • @MarkAdelsberger 你是对的,但也可以防止死锁。如果你访问了一个不可重入的锁并再次获取它,结果将是死锁。
  • 计数器不能防止死锁。完全有可能让持有锁的线程在不保留计数器的情况下通过额外的锁调用。
【解决方案2】:

当您想要调用另一个也需要锁的方法时,这有助于解决不寻常的情况。

ReentrantLock lock = new ReentrantLock();

public void doSomething() {
    lock.lock();
    try {
        // Something.
    } finally {
        lock.unlock();
    }
}

public void somethingElse () {
    lock.lock();
    try {
        // Something else.
        // We can now call another locking method without risking my lock being released.
        doSomething();
    } finally {
        lock.unlock();
    }
}

这里public可以调用doSomething,当unlock被调用时,它会获取锁,做这件事然后释放锁。

但是,当调用somethingElse 并调用doSomething 时,它只会增加锁定计数。当doSomething 解锁时不释放锁,它只是倒计时,将最终解锁留在somethingElse 中以释放锁。

【讨论】:

  • 我们不能有其他锁来保护 doSomething() 吗?是因为性能问题吗?
  • @PeerNet 如果你喜欢。但是你为什么要这样呢?
  • 我想理清头绪。如果我们没有 ReentrantLock,我们可以使用其他 Lock 对象,对吧?我想了解 ReentrantLock 的需求,它为我们提供了什么?不创建另一个锁并节省一些空间?
【解决方案3】:

增加锁的计数的目的是跟踪线程获得锁的次数,以便在线程指示准备好释放相同次数的锁之前,不会真正释放锁.

假设锁定命令将与释放锁定命令相匹配。

假设我的代码进入 Code Section A,这需要锁定。

然后在不退出代码段 A 的情况下,它进入代码段 B,需要相同的锁。正如你所说,我们有锁,所以我们不需要阻塞。

但是我们将离开 B 节,而 B 节的编写是为了在我们退出时释放锁。 (否则在没有锁的情况下到达 Section B 的代码永远不会释放锁。)

不过,我们仍处于 A 部分,因此我们还不想真的放弃锁定,否则当我们处于 A 部分时,另一个线程可能会占用它。 p>

因此,当我们进入 Section B 时,我们增加了锁计数,这意味着当我们退出 Section B 时,我们可以将计数减一,并且看到它没有回到 0,就不要释放它。

然后当 Section A 再次释放锁时,计数回落到 0,是我们真正释放锁的时候。

【讨论】:

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