学而实习之 不亦乐乎

Android:多线程设计之 wait() 和notify() 机制

2022-07-05 11:49:46

通常,多线程之间需要协调工作。例如,浏览器的一个显示图片的线程 displayThread 想要执行显示图片的任务,必须等待下载线 程downloadThread将该图片下载完毕。如果图片还没有下载完,displayThread 可以暂停,当 downloadThread 完成了任 务后,再通知 displayThread 图片准备完毕,此时,displayThread 方可执行。

以上逻辑简单的说就是:如果条件不满足,则等待。当条件满足时,等待该条件的线程将被唤醒。在Java中,这个机制的实现依赖于 wait/notify。等待机制与锁机制是密切关联的。

如:

synchronized(obj) {
    while(!condition) {
        obj.wait();
    }
    obj.doSomething();
}
  1. 当线程 A 获得了 obj 锁后,发现条件 condition 不满足,无法继续下一处理,于是线程A就wait()。
  2. 在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程 A :
synchronized(obj) {
    condition = true;
    obj.notify();
}

需要注意的概念是

  1. 调用 obj 的wait(), notify()方法前,必须获得 obj 锁,也就是必须写在 synchronized(obj){…} 代码段内。
  2. 调用 obj.wait() 后,线程A就释放了obj的锁,否则线程 B 无法获得 obj 锁,也就无法在 synchronized(obj){…} 代码段内唤醒A。
  3. 当 obj.wait()方法返回后,线程A需要再次获得 obj 锁,才能继续执行。
  4. 如果 A1,A2,A3 都在obj.wait(),则 B 调用 obj.notify() 只能唤醒 A1,A2,A3 中的一个(具体哪一个由JVM决定)。
  5. obj.notifyAll() 则能全部唤醒 A1,A2,A3,但是要继续执行 obj.wait() 的下一条语句,必须获得 obj 锁,因此, A1,A2,A3 只有一个有机会获得锁继续执行,例如 A1,其余的需要等待 A1 释放 obj 锁之后才能继续执行。
  6. 当 B 调用 obj.notify/notifyAll 的时候,B正持有obj锁,因此,A1,A2,A3 虽被唤醒,但是仍无法获得 obj 锁。直到B退出 synchronized 块,释放 obj 锁后, A1,A2,A3 中的一个才有机会获得锁继续执行。