“嗨,阿米戈!”
“嗨,里希!”
“我将向您介绍 Object 类的wait、notify和notifyAll方法。”
“今天我们只是熟悉一下它们,但我们稍后会回来,花更多时间在这上面。”
“好的。”
“这些方法是作为线程同步机制的一部分而发明的。”
“让我提醒你,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() 方法的改编:”
等待() 方法 | 解释 |
---|---|
|
线程“冻结”,但在等待作为参数传递给方法的毫秒数后,它会自动“解冻”。 |
|
线程“冻结”,但在等待作为参数传递给方法的纳秒数后,它会自动“解冻”。 |
“我们也将其称为超时等待。该方法的工作方式与普通等待一样,但如果指定的时间已经过去并且线程尚未被唤醒,它会自行唤醒。”