使用 wait、notify、notifyAl! 方法时需要注意哪些问题?
在使用wait, notify, notifyAll时,有几个重要的注意事项:
- 这些方法必须在同步代码块或同步方法中使用,也就是说,你必须已经获取到对象的锁才能调用这些方法。如果在非同步代码块或方法中调用这些方法,Java会抛出IllegalMonitorStateException。
-
调用wait方法后,当前线程会释放对象锁,进入等待状态。直到其他线程调用同一个对象的notify或notifyAll方法,当前线程才有可能被唤醒。注意我说的是“有可能”,因为如果有多个线程在等待,notify只会随机唤醒一个,而notifyAll会唤醒所有等待的线程,但只有一个线程可以获取到锁并继续执行。
-
被唤醒后的线程不会立刻执行,而是变成了就绪状态,等待CPU调度。只有当线程获取到CPU时间片后,才会继续从wait方法后的代码继续执行。
-
调用wait方法后,线程会进入等待状态,但并不会释放Thread对象的锁(如果有的话)。这意味着,其他线程仍然无法调用该Thread对象的同步方法。这一点在设计多线程应用时需要特别注意。
-
在调用wait方法时,推荐总是使用在while循环中,而不是if语句,检查条件是否满足。这是因为线程可能会出现假唤醒,也就是没有收到notify通知,或者条件未满足,但wait方法就返回了。使用while循环可以在这种情况下重新检查条件,防止出现错误。
举个例子,假设我们有一个生产者消费者问题,其中有一个共享的缓冲区。生产者在缓冲区满了后需要等待,消费者在缓冲区空了后需要等待。我们可以使用wait和notify来实现这个功能。当生产者发现缓冲区满了,就调用缓冲区对象的wait方法等待;消费者发现缓冲区空了,就调用缓冲区对象的wait方法等待。当生产者向缓冲区添加了新的产品,就调用notifyAll方法唤醒等待的消费者;消费者从缓冲区取走了产品,就调用notifyAll方法唤醒等待的生产者。