gpt4 book ai didi

java - 可重入锁 - 为什么我们需要多次获取锁?

转载 作者:行者123 更新时间:2023-12-02 01:22:31 25 4
gpt4 key购买 nike

我最近在学习java中的多线程概念。我有一些疑问,通过在 StackOverflow 上查找相关线程并没有解决。我无法为以下问题找到满意的答案:

  1. wait() 方法使线程等待,直到获得锁。而 wait(long timeout) 方法使线程等待“超时”。毫秒,如果仍然没有获得锁定,则返回到可运行状态。但要真正进入运行状态,它需要锁。那么 wait(long timeout) 方法有什么意义呢?然而,当线程处于等待状态时,它会释放它所获取的锁。所以差别甚至不在于它获得的资源。线程处于等待状态或可运行状态有什么区别? wait(long timeout) 相对于 wait() 方法有什么优势?

  2. synchronized 关键字或 block 提供对调用该方法或 block 的对象的锁定。它会导致尝试获取同一实例上的锁的另一个线程等待。但是对于ReentrantLock,锁是在哪个对象上获取的呢?试图获取谁的锁的线程会被等待?

  3. ReentrantLock 如何避免死锁?假设有两个方法m1和m2。两者都需要获取锁。 m1 正在调用 m2,m2 正在调用 m1。在这种情况下我们如何使用ReentrantLock避免死锁呢?也许我们可以使用 tryLock() 并为未能获取锁的线程提供替代操作。但可能的替代操作是什么?如果线程必须需要锁才能工作怎么办?

  4. 我发现使用ReentrantLock我们可以多次获取锁。但为什么我们必须多次获取锁呢?我已经阅读了这方面的理论答案,但无法真正理解。如果您能用清晰的示例代码进行演示,将会很有帮助。

最佳答案

Why do we need to acquire a lock multiple times?

显然,您不需要这样做。但应用程序“意外”执行此操作的情况并不罕见。例如:

  public void binaryOperation(Operand op1, Operand op2) {
synchronized (op1) {
synchronized (op2) {
// do something that needs the locks
}
}
}

// now call passing the same object for both operands
Operand op = ...
binaryOperation(op, op);

在此示例中,op 对象实际上会被锁定两次。如果原始锁不可重入,则可能会失败(或死锁)。

现在我们可以修复binaryOperation方法以不这样做,但这会使代码变得更加复杂。

使用 ReentrantLock 也会发生同样的情况。

<小时/>

问题 1。

But to actually get to running state, it needs the lock however. So what's the point of wait(long timeout) method?

这是关于Object::wait的。 ReentrantLock API 不支持此功能。 (注意:您可以在 ReentrantLock 对象上使用 waitnotify,但前提是您将其视为原始锁。这不是一个好的选择想法!)

wait 正在等待通知,timeout 表示调用者准备等待通知多长时间。作为javadoc说:

"Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed."

使用 wait()wait(timeout) 时,调用者需要检查其期望“通知”的条件是否已满足其实很满意。 (请参阅有关“虚假唤醒”的注释......以及示例代码。)

What's the advantage of wait(long timeout) over wait() method?

简单地说,它让您可以选择仅在有限的时间内等待通知。如果这没有用,请不要使用它。

<小时/>

问题 2。

But in the case of ReentrantLock, on which object is the lock acquired?

严格来说,它是锁本身。锁的实际含义取决于您如何编码类。但这与原始互斥体完全相同。

Java 中的锁定并不能阻止某些行为不当的代码在不持有锁定的情况下访问和/或更新某些共享状态。由程序员来正确地完成它。

The threads trying to acquire whose lock are made to wait?

是的。

<小时/>

问题 3。

How does a ReentrantLock avoid deadlock?

一般情况下不会。

在可重入锁定的情况下(即线程在持有锁 A 的同时尝试获取锁 A 的情况),ReentrantLock 实现会注意到持有锁的线程是获取锁 A 的线程。锁。计数器会递增,以便实现知道必须释放锁两次

How can we avoid deadlock in this situation using ReentrantLock? May be we can use tryLock() and provide an alternate operations for the thread which fails to acquire the lock.

这是一种方法。

But what could be the possible alternate operations?

  1. 确保所有线程以相同的顺序获取锁。 (当线程尝试以不同的顺序获取两个或多个线程时,就会发生死锁。)

  2. 如果 tryLock 在持有不同的锁时失败,请释放该锁,稍等片刻,然后重试。

What if the thread must need the lock to work?

然后你设计逻辑以避免死锁;请参阅上面的替代方案!

<小时/>

问题 4。

But why do we have to acquire lock several times?

如上所述,您通常不会这样做。但 ReentrantLock 的要点在于,无论出于何种原因,您都不必担心最终会两次获取锁。

关于java - 可重入锁 - 为什么我们需要多次获取锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57440851/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com