Java面试题之多线程 为什么wait和notify方法要在同步块中调用?
在Java中,wait()
和notify()
方法是用于线程间通信的关键方法,它们都属于Object
类,而不是Thread
类。为了理解为什么这两个方法必须在同步块中调用,我们需要了解几个关键概念:
监视器锁(Monitor Lock):每个对象都有一个监视器锁,只有持有该对象的锁的线程才能调用wait()
、notify()
或notifyAll()
方法。
线程安全:wait()
和notify()
方法的设计是为了在多线程环境中安全地进行线程间的协作。如果没有同步块,多个线程可能会同时访问共享资源,导致数据不一致或其他并发问题。
释放锁:当一个线程调用wait()
方法时,它会释放持有的对象锁,并进入等待状态,直到其他线程调用notify()
或notifyAll()
方法。这样,其他线程就可以获得该对象的锁并进行操作。
避免虚假唤醒:在调用wait()
后,线程会进入等待状态,直到被唤醒。为了确保线程在被唤醒后能够正确地检查条件,通常会在循环中使用wait()
,并且这个循环需要在同步块中进行,以确保在检查条件时不会被其他线程干扰。
因此,wait()
和notify()
方法必须在同步块中调用,以确保:
wait()
时,线程能够安全地释放锁,并在被唤醒后重新获得锁。示例代码:
class SharedResource {
private boolean available = false;
public synchronized void produce() throws InterruptedException {
while (available) {
wait(); // 释放锁并等待
}
available = true;
notify(); // 唤醒等待的线程
}
public synchronized void consume() throws InterruptedException {
while (!available) {
wait(); // 释放锁并等待
}
available = false;
notify(); // 唤醒等待的线程
}
}
在这个例子中,produce()
和consume()
方法都在同步块中调用wait()
和notify()
,确保了线程安全和正确的线程间通信。