调用wait()方法时发生了什么?

3
我在一本Java教材中读到了以下关于多线程的内容:
如果一个线程要调用wait()或notify(),则该线程必须是该对象锁的所有者。当线程等待时,它会暂时释放锁以供其他线程使用,但在继续执行时需要重新获取锁。
我对下面这个从句感到困惑:
当线程等待时,它会暂时释放锁以供其他线程使用
我不明白这句话在说什么。它是在说当调用wait()方法时,在wait()返回之前实际上会释放锁吗(即调用者并不知道这个过程)?还是只是在提到wait(timeout)时当超时时间结束后释放锁?如果是前者,为什么会在notify()之前释放锁呢?这似乎是一个含糊且解释不足的陈述。

2
在调用wait()之前,线程拥有锁,在调用wait()之后,线程放弃锁,并等待通知,在从wait()返回时,它再次拥有锁。始终在while()循环中调用wait(),它可以在获取锁之前和之后检查条件。请编写一个使用wait()和notify() / notifyAll()的演示以查看其工作原理,如果不亲自实现它,您将无法理解它。 - Eric
3
调用wait()(或其超时重载)必须释放锁,否则另一个线程如何获取锁以调用notify()/ notifyAll()?注意,线程通过使用synchronized(someObj){...}来获取对象的锁。 - Slaw
3个回答

4

线程调用wait()或notify()时,必须是该对象的锁的所有者。

否则,将出现运行时错误,并且代码的其余部分不会执行。

当线程等待时,它暂时释放锁以供其他线程使用。

更详细地说,调用wait()会执行以下操作:

  • 锁被释放
  • 当前线程在监视器中注册为等待
  • 处理器切换到其他准备执行的线程

然后,某个线程调用notify()或notifyAll(),这会导致已在此监视器上注册为等待的一个或多个线程从等待集合移动到就绪集合,等待空闲处理器来执行。

但它需要再次获取锁才能继续执行。

这意味着线程的执行将继续执行同步语句以重新获得锁。获得锁后,wait()方法才返回。wait(timeout)不同的是除了notify()或notifyAll()外,它还可以在超时后返回。

总之,您需要了解线程如何在以下4种状态之间切换:

  • 在处理器上运行
  • 在synchronized语句上阻塞
  • 等待通知
  • 准备执行并等待空闲处理器

1
当一个线程调用wait方法时,线程立即释放锁并进入休眠状态,直到超时时间到期(如果有)或者收到通知为止。通知是由另一个线程获取了相同的锁并调用notify方法时发生的(同时调度程序必须从等待线程中选择等待线程;调用notify不会通知给定的线程,它告诉调度程序从给定锁的等待集合中选择一个线程进行通知)。
一旦线程被notify唤醒,它必须重新获取锁才能离开wait方法,因为线程仍然在同步方法或块中。这就是引用所说的线程需要锁来恢复执行的含义。

1
当一个线程调用wait()时,它会暂时释放对象的监视器(锁),直到它接收到另一个线程的通知。这样,线程可以自愿地将对象的监视器控制权交给另一个线程。请参阅docs

调用wait()不会返回,直到另一个线程发出通知,指示可能发生了某些特殊事件 - 尽管不一定是此线程正在等待的事件(因此总是在循环内调用wait()以测试等待的条件)。

...

调用wait()时,线程释放锁并挂起执行。在将来的某个时间,另一个线程将获得相同的锁并调用Object.notifyAll,通知所有等待该锁的线程发生了重要事件。


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