基本概念
wait
和 notify
是 Java 中用于线程间通信的方法,定义在 Object
类中。它们的主要作用是在多线程环境中协调线程的执行顺序。
wait
方法
- 作用:使当前线程进入等待状态,直到其他线程调用
notify
或notifyAll
方法唤醒它。 - 调用条件:必须在同步块或同步方法中调用,因为调用
wait
方法的线程需要持有对象的监视器锁(即对象锁)。 - 锁释放:调用
wait
方法时,当前线程会释放对象的监视器锁,并进入该对象的等待队列中。
synchronized (lock) {while (!condition) {lock.wait();}// 执行后续操作
}
notify
方法
- 作用:唤醒在该对象的等待队列中等待的一个线程。如果有多个线程在等待,选择其中一个线程唤醒。
- 调用条件:必须在同步块或同步方法中调用,因为调用
notify
方法的线程需要持有对象的监视器锁。
synchronized (lock) {condition = true;lock.notify();
}
notifyAll
方法
- 作用:唤醒在该对象的等待队列中等待的所有线程。
- 调用条件:必须在同步块或同步方法中调用,因为调用
notifyAll
方法的线程需要持有对象的监视器锁。
synchronized (lock) {condition = true;lock.notifyAll();
}
使用场景:生产者-消费者模式
生产者-消费者模式是 wait
和 notify
方法的经典应用场景。在这种模式下,生产者线程生成数据,消费者线程消费数据,wait
和 notify
方法用于协调它们的工作。
示例代码
class SharedResource {private int content;private boolean available = false;public synchronized void put(int value) {while (available) {try {wait();} catch (InterruptedException e) {Thread.currentThread().interrupt();}}content = value;available = true;notify();}public synchronized int get() {while (!available) {try {wait();} catch (InterruptedException e) {Thread.currentThread().interrupt();}}available = false;notify();return content;}
}class Producer implements Runnable {private SharedResource resource;public Producer(SharedResource resource) {this.resource = resource;}public void run() {for (int i = 0; i < 10; i++) {resource.put(i);System.out.println("Produced: " + i);try {Thread.sleep((int) (Math.random() * 100));} catch (InterruptedException e) {Thread.currentThread().interrupt();}}}
}class Consumer implements Runnable {private SharedResource resource;public Consumer(SharedResource resource) {this.resource = resource;}public void run() {for (int i = 0; i < 10; i++) {int value = resource.get();System.out.println("Consumed: " + value);try {Thread.sleep((int) (Math.random() * 100));} catch (InterruptedException e) {Thread.currentThread().interrupt();}}}
}public class ProducerConsumerTest {public static void main(String[] args) {SharedResource resource = new SharedResource();Thread producerThread = new Thread(new Producer(resource));Thread consumerThread = new Thread(new Consumer(resource));producerThread.start();consumerThread.start();}
}
运行效果
这段代码展示了生产者和消费者如何通过 wait
和 notify
方法进行协调:
Produced: 0
Consumed: 0
Produced: 1
Consumed: 1
Produced: 2
Consumed: 2
...
详细解释
-
生产者线程:
- 生产者线程调用
put
方法试图放入一个值。 - 如果
available
为true
(表示已有未被消费的数据),生产者线程调用wait
方法进入等待状态,直到消费者消费了数据并唤醒它。 - 如果
available
为false
,生产者线程放入新值,设置available
为true
,并调用notify
方法唤醒一个等待的消费者线程。
- 生产者线程调用
-
消费者线程:
- 消费者线程调用
get
方法试图获取一个值。 - 如果
available
为false
(表示没有可消费的数据),消费者线程调用wait
方法进入等待状态,直到生产者放入新数据并唤醒它。 - 如果
available
为true
,消费者线程获取值,设置available
为false
,并调用notify
方法唤醒一个等待的生产者线程。
- 消费者线程调用
总结
wait
:使当前线程进入等待状态,释放对象的监视器锁。notify
:唤醒一个在该对象上等待的线程。notifyAll
:唤醒所有在该对象上等待的线程。- 同步块/同步方法:
wait
、notify
和notifyAll
必须在同步块或同步方法中调用,因为它们需要当前线程持有对象的监视器锁。 - 生产者-消费者模式:经典的
wait
和notify
用例,展示了如何协调多个线程对共享资源的访问。