推荐答案
notify() 和 notifyAll() 都是用于线程间通信的方法,主要用于唤醒在等待队列中的线程。它们的区别在于:
notify():唤醒在此对象监视器上等待的单个线程。如果有多个线程在等待,JVM 会随机选择一个线程唤醒。notifyAll():唤醒在此对象监视器上等待的所有线程。所有等待的线程都会被唤醒,但它们需要竞争锁,只有一个线程能够获得锁并继续执行。
本题详细解读
1. notify() 方法
- 作用:
notify()方法用于唤醒在对象监视器上等待的单个线程。如果有多个线程在等待,JVM 会随机选择一个线程唤醒。 - 使用场景:适用于只需要唤醒一个线程的场景,比如在生产者-消费者模型中,生产者生产了一个产品后,只需要唤醒一个消费者线程来处理。
2. notifyAll() 方法
- 作用:
notifyAll()方法用于唤醒在对象监视器上等待的所有线程。所有等待的线程都会被唤醒,但它们需要竞争锁,只有一个线程能够获得锁并继续执行。 - 使用场景:适用于需要唤醒所有等待线程的场景,比如在资源池管理中,当资源可用时,需要唤醒所有等待的线程来竞争资源。
3. 代码示例
// www.javascriptcn.com code example
public class NotifyExample {
private final Object lock = new Object();
public void waitMethod() throws InterruptedException {
synchronized (lock) {
System.out.println(Thread.currentThread().getName() + " is waiting");
lock.wait();
System.out.println(Thread.currentThread().getName() + " is notified");
}
}
public void notifyMethod() {
synchronized (lock) {
System.out.println("Notifying one thread");
lock.notify();
}
}
public void notifyAllMethod() {
synchronized (lock) {
System.out.println("Notifying all threads");
lock.notifyAll();
}
}
public static void main(String[] args) throws InterruptedException {
NotifyExample example = new NotifyExample();
Thread t1 = new Thread(() -> {
try {
example.waitMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
example.waitMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
Thread.sleep(1000);
example.notifyMethod(); // 只唤醒一个线程
// example.notifyAllMethod(); // 唤醒所有线程
}
}4. 注意事项
notify()和notifyAll()必须在同步代码块或同步方法中调用,否则会抛出IllegalMonitorStateException。- 使用
notify()时,无法控制具体唤醒哪个线程,可能会导致某些线程长时间得不到执行。 - 使用
notifyAll()时,所有等待的线程都会被唤醒,但只有一个线程能够获得锁并继续执行,其他线程会重新进入等待状态。