java Java中的“ReentrantLock”是什么意思?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16504231/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 23:09:02  来源:igfitidea点击:

What is the meaning of "ReentrantLock" in Java?

javareentrancy

提问by znlyj

Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.

重入意味着锁是在每个线程而不是每个调用的基础上获取的。

Since an intrinsic lock is held by a thread, doesn't it mean that a thread run once equals an invocation basis?

既然内在锁是由线程持有的,是不是就意味着一个线程运行一次就等于一个调用基础?

Thank you, it seems mean that: in a thread,if I get a lock lockAwhen process function doAwhich call function doB, and doBalso need a lock lockA,then there wil be a reentrancy. In Java, this phenomenon is acquired per thread, so I needn't consider deadlocks?

谢谢,好像是说:在一个线程中,如果我lockA在处理doA调用函数的函数时得到了一个锁doB,并且doB也需要一个锁lockA,那么就会出现重入。在Java中,这种现象是每个线程都获得的,所以我不需要考虑死锁吗?

回答by Stephen C

Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.

重入意味着锁是在每个线程而不是每个调用的基础上获取的。

That is a misleading definition. It is true (sort of), but it misses the real point.

这是一个误导性的定义。这是真的(有点),但它没有抓住真正的重点。

Reentrancy means (in general CS / IT terminology) that you do something, and while you are still doing it, you do it again. In the case of locks it means you do something like this on a single thread:

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

  1. Acquire a lock on "foo".
  2. Do something
  3. Acquire a lock on "foo". Note that we haven't released the lock that we previously acquired.
  4. ...
  5. Release lock on "foo"
  6. ...
  7. Release lock on "foo"
  1. 获得对“foo”的锁定。
  2. 做一点事
  3. 获得对“foo”的锁定。请注意,我们还没有释放我们之前获得的锁。
  4. ...
  5. 释放对“foo”的锁定
  6. ...
  7. 释放对“foo”的锁定

With a reentrant lock / locking mechanism, the attempt to acquire the same lock will succeed, and will increment an internal counter belonging to the lock. The lock will only be released when the current holder of the lock has released it twice.

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

Here's a example in Java using primitive object locks / monitors ... which are reentrant:

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

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

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

The alternative to reentrant is non-reentrant locking, where it would be an error for a thread to attempt to acquire a lock that it already holds.

可重入的替代方法是不可重入锁定,在这种情况下,线程尝试获取它已经持有的锁将是错误的。

The advantage of using reentrant locks is that you don't have to worry about the possibility of failing due to accidentally acquiring a lock that you already hold. The downside is that you can't assume that nothing you call will change the state of the variables that the lock is designed to protect. However, that's not usually a problem. Locks are generally used to protect against concurrent state changes made by otherthreads.

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



So I needn't consider deadlocks?

所以我不需要考虑死锁?

Yes you do.

是的你是。

A thread won't deadlock against itself (if the lock is reentrant). However, you could get a deadlock if there are other threads that might have a lock on the object you are trying to lock.

线程不会对自身造成死锁(如果锁是可重入的)。但是,如果有其他线程可能锁定了您要锁定的对象,则可能会出现死锁。

回答by Patashu

Imagine something like this:

想象一下这样的事情:

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

function B():
    A()

Now we call A. The following happens:

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

  • We enter A, locking X
  • We enter B
  • We enter A again, locking X again
  • 我们输入A,锁定X
  • 我们输入B
  • 我们再次输入 A,再次锁定 X

Since we never exited the first invocation of A, X is still locked. This is called re-entrance - while function A has not yet returned, function A is called again. If A relies on some global, static state, this can cause a 're-entrance bug', where before the static state is cleaned up from the function's exit, the function is run again, and the half computed values collide with the start of the second call.

由于我们从未退出 A 的第一次调用,因此 X 仍然被锁定。这称为重入 - 当函数 A 尚未返回时,再次调用函数 A。如果 A 依赖于一些全局的静态状态,这可能会导致“重入错误”,在从函数的退出清除静态状态之前,该函数再次运行,并且一半的计算值与第二个电话。

In this case, we run into a lock we are already holding. If the lock is re-entrance aware, it will realize we are the same thread holding the lock already and let us through. Otherwise, it will deadlock forever - it will be waiting for a lock it already holds.

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

In java, lockand synchronizedare re-entrance aware - if a lock is held by a thread, and the thread tries to re-acquire the same lock, it is allowed. So if we wrote the above pseudocode in Java, it would not deadlock.

在 java 中,lock并且synchronized是重入感知的——如果一个锁被一个线程持有,并且该线程试图重新获取相同的锁,那么它是允许的。所以如果我们用Java写上面的伪代码,就不会死锁。

回答by Aniket Thakur

Java concurrency in practice book states - Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.

Java 并发实践书指出 - Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.

Let me explain what it exactly means. First of all Intrinsic locks are reentrant by nature. The way reentrancy is achieved is by maintaining a counter for number of locks acquired and owner of the lock. If the count is 0 and no owner is associated to it, means lock is not held by any thread. When a thread acquires the lock, JVM records the owner and sets the counter to 1.If same thread tries to acquire the lock again, the counter is incremented. And when the owning thread exits synchronized block, the counter is decremented. When count reaches 0 again, lock is released.

让我解释一下它的确切含义。首先,内在锁本质上是可重入的。实现可重入的方法是维护获取的锁数量和锁所有者的计数器。如果计数为 0 并且没有所有者与之关联,则意味着任何线程都没有持有锁。当线程获取锁时,JVM 记录所有者并将计数器设置为 1。如果同一线程再次尝试获取锁,则计数器递增。当拥有线程退出同步块时,计数器递减。当计数再次达到 0 时,锁被释放。

A simple example would be -

一个简单的例子是——

public class Test {
    public synchronized void performTest() {
       //...
    }
}

public class CustomTest extends Test {
    public synchronized void performTest() {
       //...
       super.performTest();
    }
}

without reentrancy there would be a deadlock.

如果没有可重入性,就会出现僵局。

enter image description here

在此处输入图片说明

回答by Jeewantha Samaraweera

Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.

重入意味着锁是在每个线程而不是每个调用的基础上获取的。

Let me explain this with an example.

让我用一个例子来解释这一点。

class ReentrantTester {

    public synchronized void methodA() {
      System.out.println("Now I am inside methodA()");
      methodB();
    }

    public synchronized void methodB() {
      System.out.println("Now I am inside methodB()");
    }

    public static void main(String [] args) {
        ReentrantTester rt = new ReentrantTester();
        rt.methodA();  
    }

}

The out put is :

输出是:

Now I am inside methodA()
Now I am inside methodB()

As in the above code, the ReentrantTester contains two synchronized methods: methodA() & methodB() The first synchronized method methodA() calls the other synchronized method methodB().

和上面的代码一样,ReentrantTester 包含两个同步方法:methodA() & methodB() 第一个同步方法methodA()调用另一个同步方法methodB()。

When execution enters the methodA(), the current thread acquires the monitor for the ReentrantTester object. Now when methodA() calls methodB(), because methodB() is also synchronized, the thread attempts to acquire the same monitor again. Because Java supports reentrant monitors, this works. The current thread acquire the ReentrantTester's monitor again and continue the execution of both methodA() and methodB().

当执行进入methodA()时,当前线程获取ReentrantTester对象的监视器。现在当methodA()调用methodB()时,因为methodB()也是同步的,线程再次尝试获取同一个监视器。因为 Java 支持可重入监视器,所以这是有效的。当前线程再次获取 ReentrantTester 的监视器并继续执行 methodA() 和 methodB()。

The Java runtime allows a thread to reacquire a monitor that it already holds, because Java monitors are reentrant. These reentrant monitors are important because they eliminate the possibility of a single thread deadlocking itself on a monitor that it already holds.

Java 运行时允许线程重新获取它已经拥有的监视器,因为 Java 监视器是可重入的。这些可重入监视器很重要,因为它们消除了单个线程在它已经拥有的监视器上死锁的可能性。

回答by rubixibuc

This just means once a thread has a lock it may enter the locked section of code as many times as it needs to. So if you have a synchronized section of code such as a method, only the thread which attained the lock can call that method, but can call that method as many times as it wants, including any other code held by the same lock. This is important if you have one method that calls another method, and both are synchronized by the same lock. If this wasn't the case the. The second method call would block. It would also apply to recursive method calls.

这只是意味着一旦一个线程获得了锁,它就可以根据需要多次进入被锁定的代码段。因此,如果您有代码的同步部分,例如方法,则只有获得锁的线程才能调用该方法,但可以根据需要多次调用该方法,包括由同一锁​​持有的任何其他代码。如果您有一个方法调用另一个方法,并且两者都由同一个锁同步,那么这一点很重要。如果不是这种情况。第二个方法调用会阻塞。它也适用于递归方法调用。

public void methodA()
{
     // other code
     synchronized(this)
     {
          methodB();
     } 
}

public void methodB()
{
     // other code
     syncrhonized(this)
     {
          // it can still enter this code    
     }

}

回答by igoneHyman

it's about recurse, think about:

这是关于递归的,请考虑:

private lock = new ReentrantLock();
public void method() {
      lock.lock();
      method();
}

If the lock is not re-entrant able, the thread could block itself.

如果锁不可重入,则线程可能会阻塞自身。