Java:如果在释放锁之前始终调用notify(),那么等待的线程如何获取相同的锁?

9

我觉得我已经知道那个问题的答案了,但我想读一下你们的看法,以确保我真正理解Java线程状态机(或图表)是如何工作的。

想象一下,线程A在返回给定值之前运行notify()

public class baz{

    // Thread B runs this:
    public synchronized void bar(){
       wait();
    } 

    // Thread A runs this:
    public synchronized int foo(){
       notify();
       return 11;
    }
}

在Thread A释放锁之前(即在“return 11”语句之后),将调用notify()。那么,等待此锁的线程B(通过wait()方法)如何获得仍由Thread A持有的锁呢?请注意,当线程B被通知时,Thread A尚未释放锁。
因此,我认为这种情况如下所示: 调用wait()后,Thread B将其状态从Running更改为Waiting。 收到来自Thread A notify()方法的通知后,Thread B将从wait()返回,将其状态更改为Runnable并尝试获取锁定。由于锁仍未被Thread A释放,因此Thread B将在对象的监视器上被阻止,并将其状态从Runnable更改为Blocked。 最终,在Thread A释放锁后,Thread B将获取锁并将其状态从Blocked更改为Running
这样理解是正确的吗?我想通过这个问题了解一个经由已经获得的锁同步的wait()返回的线程会发生什么。
1个回答

2

是的,你的解释是正确的。

当你在一个对象上调用wait()时,调用线程将被添加到该对象的等待集中。当它被notify()通知后,它将从等待集中移除,并在该对象上执行锁定操作(它在该对象的同步块内)。该锁定操作将阻塞当前线程直到完成,即锁定了对象监视器。

这与两个线程尝试进入同一对象的synchronized块时的行为完全相同。第一个到达的线程将锁定对象监视器,立即完成锁定对象。其他线程将被阻塞,直到其锁定操作完成,即在第一个线程解锁监视器之后。


这是什么意思:return语句不能释放锁?问题的例子可能是死锁吗?我们不应该在同步方法中使用return语句吗?你能解释一下或给我一个链接来澄清我的这些概念吗? - Asif Mushtaq
@UnKnown return语句本身并不释放锁。如果return语句出现在synchronized块或方法中,那么实际上是由于离开该块或方法而导致锁被释放。 - Sotirios Delimanolis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接