一个简单的生产者和消费者模型
代码语言:javascript复制import java.util.LinkedList;
public class ProducerConsumerExample {
public static void main(String[] args) throws InterruptedException {
final Buffer buffer = new Buffer(5); // 创建一个缓冲区,容量为5
// 创建一个生产者线程
Thread producerThread = new Thread(() -> {
try {
int value = 0;
while (true) {
buffer.put(value ); // 生产一个数据到缓冲区
Thread.sleep(1000); // 等待1秒钟
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 创建一个消费者线程
Thread consumerThread = new Thread(() -> {
try {
while (true) {
int value = buffer.take(); // 从缓冲区中取出一个数据
System.out.println("Consumed: " value);
Thread.sleep(2000); // 等待2秒钟
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 启动生产者和消费者线程
producerThread.start();
consumerThread.start();
// 等待线程结束
producerThread.join();
consumerThread.join();
}
// 缓冲区类
static class Buffer {
private final LinkedList<Integer> queue; // 用链表实现缓冲区
private final int capacity; // 缓冲区容量
public Buffer(int capacity) {
this.queue = new LinkedList<>();
this.capacity = capacity;
}
// 生产一个数据
public void put(int value) throws InterruptedException {
synchronized (queue) {
while (queue.size() == capacity) { // 缓冲区已满,等待消费者消费
queue.wait();
}
queue.add(value);
queue.notifyAll(); // 通知消费者可以消费了
}
}
// 消费一个数据
public int take() throws InterruptedException {
synchronized (queue) {
while (queue.isEmpty()) { // 缓冲区为空,等待生产者生产
queue.wait();
}
int value = queue.remove();
queue.notifyAll(); // 通知生产者可以生产了
return value;
}
}
}
}
我们常用的 LinkedList 就可以当队列使用,实现了Dequeue接口,还有 ConcurrentLinkedQueue,他们都属于非阻塞队列
说明
创建了一个缓冲区类Buffer,它使用一个链表来实现缓冲区,并且具有生产和消费两个方法put()和take()。在put()方法中,如果缓冲区已满,就等待消费者消费;否则,将数据加入缓冲区,并通知消费者可以消费了。在take()方法中,如果缓冲区为空,就等待生产者生产;否则,从缓冲区中取出一个数据,并通知生产者可以生产了。
在main()方法中创建了一个缓冲区对象,并创建了一个生产者线程和一个消费者线程。生产者线程不断地生产数据,并将其放入缓冲区中;消费者线程不断地从缓冲区中取出数据,并打印出来。我们通过调整生产者和消费者的等待时间,可以观察到生产者和消费者之间的交互过程。
扩展
在多线程中阻塞队列的使用非常常见,例如LinkedBlockingQueue中就使用的不是synchronized关键字,而是用的ReentrantLock,结合Condition来用的,此时了解synchronized和lock的区别也就有必要了