在Java并发编程中,“等待-通知”机制是解决线程间通信的一种常用方法。这种机制通常用于解决生产者-消费者模式中的问题,以及其他需要线程间同步通信的场景。下面我将详细介绍如何使用“等待-通知”机制来优化循环等待,并通过示例代码来展示其实现过程。
1. “等待-通知”机制概述
“等待-通知”机制主要包括两个部分:
- 等待(Wait):线程调用对象的
wait()
方法进入等待状态,释放该对象的锁,并等待其他线程的通知。 - 通知(Notify/NotifyAll):线程调用对象的
notify()
或notifyAll()
方法唤醒正在等待该对象锁的一个或所有线程。
2. 优化循环等待
在没有使用“等待-通知”机制的情况下,线程可能会陷入无限循环,不断地检查某个条件是否满足。这种循环等待不仅浪费CPU资源,而且效率低下。使用“等待-通知”机制可以避免这种情况,让线程在条件不满足时暂停,等到条件满足时再恢复执行。
3. 示例代码
下面通过一个简单的生产者-消费者模式的示例来展示如何使用“等待-通知”机制来优化循环等待。
3.1 生产者-消费者模式
假设我们有一个缓冲区,生产者向缓冲区添加元素,消费者从缓冲区取出元素。我们需要确保缓冲区不会溢出也不会为空。
3.2 示例代码
public class Buffer {
private final int capacity = 10;
private final Object[] items = new Object[capacity];
private int putIndex = 0;
private int takeIndex = 0;
private int count = 0;
public synchronized void put(Object item) {
while (count == capacity) {
try {
wait(); // 缓冲区已满,等待消费者消费
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
items[putIndex] = item;
if (++putIndex == capacity) {
putIndex = 0;
}
++count;
notifyAll(); // 通知消费者可以消费了
}
public synchronized Object take() {
while (count == 0) {
try {
wait(); // 缓冲区为空,等待生产者生产
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
Object item = items[takeIndex];
if (++takeIndex == capacity) {
takeIndex = 0;
}
--count;
notifyAll(); // 通知生产者可以生产了
return item;
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
final Buffer buffer = new Buffer();
Thread producer = new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(100); // 模拟生产时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
buffer.put(new Object());
System.out.println("Produced: " + i);
}
});
Thread consumer = new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(200); // 模拟消费时间
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Object item = buffer.take();
System.out.println("Consumed: " + i);
}
});
producer.start();
consumer.start();
try {
producer.join();
consumer.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4. 代码解释
-
Buffer 类:
- 定义了一个固定大小的缓冲区
items
,用于存放生产者生产的元素。 put
方法用于生产者向缓冲区添加元素。当缓冲区已满时,线程调用wait()
方法进入等待状态,直到收到notifyAll()
信号。take
方法用于消费者从缓冲区取出元素。当缓冲区为空时,线程调用wait()
方法进入等待状态,直到收到notifyAll()
信号。synchronized
关键字用于保证线程安全,确保任何时候只有一个线程可以访问put
或take
方法。
- 定义了一个固定大小的缓冲区
-
ProducerConsumerDemo 类:
- 创建了一个
Buffer
实例。 - 启动了一个生产者线程和一个消费者线程。
- 生产者线程每100毫秒生产一个元素,消费者线程每200毫秒消费一个元素。
- 使用
join()
方法等待两个线程完成。
- 创建了一个
5. 总结
通过使用“等待-通知”机制,我们可以有效地避免线程间的循环等待,提高程序的效率和响应速度。在生产者-消费者模式中,这种方法尤其有用,因为它可以确保生产者和消费者之间有良好的协调,避免缓冲区溢出或空闲的情况。
如果你有任何疑问或需要进一步的解释,请随时提问!