“嗨,阿米戈!”

“嗨,里希!”

“我将向您介绍 Object 类的waitnotifynotifyAll方法。”

“今天我们只是熟悉一下它们,但我们稍后会回来,花更多时间在这上面。”

“好的。”

“这些方法是作为线程同步机制的一部分而发明的。”

“让我提醒你,Java 有一个内置的机制来控制不同线程对共享资源(对象)的访问。一个线程可以声明一个对象处于忙碌状态,其他线程将不得不等待,直到这个忙碌的对象被释放。 “

“我记得。你用同步关键字来做到这一点。”

“对。通常,代码看起来像这样:”

public void print()
{
 Object monitor = getMonitor();
 synchronized(monitor)
 {
  System.out.println("text");
 }
}

“还记得它是如何工作的吗?”

“是的。如果两个线程同时调用 print() 方法,其中一个线程将进入标记为 synchronized 的块并锁定监视器,这使得第二个线程将等待直到监视器被释放。”

“对。一旦一个线程进入标记为synchronized的块,monitor对象就被标记为busy,其他线程将被迫等待monitor对象被释放。同一个monitor对象可以在程序的各个部分使用。 “

“对了,你为什么选择班长这个名字?”

“监视器就是您通常所说的存储忙碌或空闲状态的对象。”

“这就是等待通知方法发挥作用的地方。”

“其实,真的就只有这两种方法,其他的都是这些方法的改编而已。”

“现在让我们来了解一下wait 方法是什么以及我们为什么需要它。

“有时在程序中会出现这样的情况,线程进入同步代码块并锁定监视器,但由于缺少某些数据而无法继续执行。例如,它需要处理的文件尚未完成下载或像那样的东西。”

“我们可以等待文件下载。您可以使用循环检查它。如果文件尚未下载,则休眠一秒钟左右,然后再次检查,直到下载完成。”

“像这样的东西:”

while(!file.isDownloaded())
{
 Thread.sleep(1000);
}
processFile(file);

“但在我们的例子中,这种等待的代价太大了。由于我们的线程锁定了监视器,其他线程也被迫等待,即使它们可能已经拥有所需的数据。”

“发明了wait()方法来解决这个问题。这个方法导致线程释放监视器,然后 «suspends» 线程。

“您只能在监视器繁忙时调用监视器对象的 wait 方法,即只能在同步块内。发生这种情况时,线程会暂时停止运行,并释放监视器,以便其他线程可以使用它。”

“通常情况下,线程会进入同步块并调用等待,从而释放监视器。”

“然后第二个线程将进入并暂停,然后是第三个,依此类推。”

“线程如何恢复?”

“为此,还有第二种方法:通知。”

“您只能在监视器繁忙时调用监视器对象的notify / notifyAll方法,即只能在同步块内调用。notifyAll方法唤醒所有等待此监视器对象的线程。”

notify方法‘解冻’了一个随机线程,但notifyAll方法解冻了该监视器的所有 «frozen» 线程。”

“非常有趣。谢谢你,Rishi。”

“还有对 wait() 方法的改编:”

等待() 方法 解释
void wait(long timeout)
线程“冻结”,但在等待作为参数传递给方法的毫秒数后,它会自动“解冻”。
void wait(long timeout, int nanos)
线程“冻结”,但在等待作为参数传递给方法的纳秒数后,它会自动“解冻”。

“我们也将其称为超时等待。该方法的工作方式与普通等待一样,但如果指定的时间已经过去并且线程尚未被唤醒,它会自行唤醒。”