Java中“ReentrantLock”的含义是什么?

2022-08-31 23:53:19

重入意味着锁是按线程而不是按调用获取的。

既然固有锁是由线程持有的,这难道不意味着线程运行一次等于调用基础吗?

谢谢,它似乎意味着:在一个线程中,如果我在处理函数时得到一个锁,哪个调用函数,并且还需要一个锁,那么就会有一个重入。在Java中,这种现象是按线程获取的,所以我不需要考虑死锁吗?lockAdoAdoBdoBlockA


答案 1

重入意味着锁是按线程而不是按调用获取的。

这是一个误导性的定义。这是真的(某种程度上),但它错过了真正的重点。

重入意味着(一般CS / IT术语)你做了某事,当你还在做的时候,你又做了一次。在锁的情况下,这意味着你在单个线程上做这样的事情:

  1. 在“foo”上获取锁定。
  2. 做点什么
  3. 在“foo”上获取锁定。请注意,我们尚未释放以前获取的锁。
  4. ...
  5. 释放“foo”上的锁
  6. ...
  7. 释放“foo”上的锁

使用重入锁定/锁定机制,尝试获取相同的锁定将成功,并将增加属于该锁的内部计数器。只有当锁的当前持有者释放了两次锁时,才会释放锁。

这是Java中使用原始对象锁/监视器的示例...可重入的:

Object lock = new Object();
...
synchronized (lock) {
    ...
    doSomething(lock, ...)
    ...
}

public void doSomething(Object lock, ...) {
    synchronized (lock) {
        ...
    }
}

重入锁定的替代方法是非重入锁定,其中线程尝试获取已持有的锁定将是错误的。

使用重入锁的优点是,您不必担心由于意外获取已持有的锁而失败的可能性。缺点是,您不能假设您调用的任何内容都不会更改锁旨在保护的变量的状态。但是,这通常不是问题。锁通常用于防止其他线程进行并发状态更改。


所以我不需要考虑死锁?

是的,你有。

线程不会对自身进行死锁(如果锁是可重入的)。但是,如果存在其他线程可能对您尝试锁定的对象具有锁定,则可能会出现死锁。


答案 2

想象一下这样的事情:

function A():
   lock (X)
       B()
   unlock (X)

function B():
    A()

现在我们称之为A。将发生以下情况:

  • 我们输入 A,锁定 X
  • 我们进入 B
  • 我们再次输入 A,再次锁定 X

由于我们从未退出 A 的第一次调用,因此 X 仍处于锁定状态。这称为重新进入 - 当函数 A 尚未返回时,再次调用函数 A。如果 A 依赖于某个全局静态状态,这可能会导致“重新进入 bug”,在从函数的退出中清理静态状态之前,函数将再次运行,并且计算的一半值与第二次调用的开始发生冲突。

在这种情况下,我们遇到了一个我们已经持有的锁。如果锁是重新进入感知的,它将意识到我们已经是持有锁的同一根线,并让我们通过。否则,它将永远死锁 - 它将等待它已经持有的锁。

在java中,并且是可重新进入的 - 如果一个锁被一个线程持有,并且该线程试图重新获取相同的锁,则允许它。因此,如果我们用Java编写上述伪代码,它不会死锁。locksynchronized


推荐