介绍
在 Java 多线程编程中,wait、notify 和 notifyAll 是用于线程间通信的重要方法。它们是在 Object 类中定义的,因此每个 Java 对象都可以使用这些方法。本文将通过一个实际应用场景来介绍它们的使用。
- wait:当线程调用 wait 方法时,它会释放对象的锁,并进入等待状态,直到被其他线程唤醒。
- notify:notify 方法唤醒一个正在等待该对象锁的线程。如果有多个线程等待,则随机唤醒一个。
- notifyAll:notifyAll 方法唤醒所有等待该对象锁的线程,让它们重新竞争锁。
实际应用
假设我们有一个简单的生产者-消费者问题。生产者线程负责生成数据,而消费者线程负责处理数据。为了协调两者的运行,我们需要使用 wait 和 notify 来管理它们之间的通信。
class ProducerConsumer {
private final Queue<Integer> queue = new LinkedList<>();
private final int MAX_CAPACITY = 10;
private int producedCount = 0;
// 停止生产
private volatile boolean produceStop = false;
public void produce() throws InterruptedException {
int value = 1;
while (!produceStop) {
synchronized (this) {
while (queue.size() == MAX_CAPACITY) {
System.out.println("Queue is full, waiting for consumer to consume...");
wait();
}
if (producedCount >= 50) {
produceStop = true;
break;
}
System.out.println("Thread: " + Thread.currentThread().getName() + " Produced: " + value);
queue.add(value++);
producedCount++;
notify(); // Notify consumer thread
}
Thread.sleep(250);
}
}
public void consume() throws InterruptedException {
while (true){
synchronized (this) {
if (queue.isEmpty() && produceStop) {
System.out.println("Consumer thread finished.");
break;
}
while (queue.isEmpty()) {
System.out.println("Queue is empty, waiting for producer to produce...");
wait();
}
int value = queue.poll();
System.out.println("Thread: " + Thread.currentThread().getName() + " Consumed: " + value);
notify(); // Notify producer thread
}
Thread.sleep(500);
}
}
}
public class Main {
public static void main(String[] args) {
ProducerConsumer pc = new ProducerConsumer();
Thread producerThread = new Thread(() -> {
try {
pc.produce();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("Producer thread was interrupted.");
}
});
Thread consumerThread = new Thread(() -> {
try {
pc.consume();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("Consumer thread was interrupted.");
}
});
producerThread.start();
consumerThread.start();
}
}
程序解释
1、共享资源:我们使用一个 LinkedList 作为共享队列,最大容量为 10。
2、生产者方法:produce 方法在队列未满时添加数据,并在添加后调用 notify 唤醒消费者。
3、消费者方法:consume 方法在队列不为空时取出数据,并在取出后调用 notify 唤醒生产者。
4、同步块:synchronized 关键字用于确保对共享资源的线程安全访问。
5、等待条件:while 循环用于检查队列状态,以防止被错误唤醒(过早唤醒)。
6、while 循环:确保线程在每次被唤醒时都会重新检查条件,防止过早通知导致的错误操作。