Java面试题之多线程 用Java实现阻塞队列
在Java中,阻塞队列是一种支持在队列为空时等待取出元素的队列,或者在队列满时等待插入元素的队列。Java的标准库中已经提供了java.util.concurrent
包下的BlockingQueue
接口及其实现类(如ArrayBlockingQueue
、LinkedBlockingQueue
等),但我们可以自己实现一个简单的阻塞队列来加深理解。
下面是一个简单的阻塞队列的实现,使用了wait()
和notifyAll()
来实现线程间的通信。
import java.util.LinkedList;
public class BlockingQueue<T> {
private final LinkedList<T> queue = new LinkedList<>();
private final int capacity;
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
// 入队
public synchronized void put(T item) throws InterruptedException {
while (queue.size() == capacity) {
wait(); // 队列满,等待
}
queue.add(item);
notifyAll(); // 通知其他等待的线程
}
// 出队
public synchronized T take() throws InterruptedException {
while (queue.isEmpty()) {
wait(); // 队列空,等待
}
T item = queue.removeFirst();
notifyAll(); // 通知其他等待的线程
return item;
}
// 获取当前队列大小
public synchronized int size() {
return queue.size();
}
}
下面是一个使用BlockingQueue
的示例,展示了如何在生产者-消费者模型中使用它。
public class ProducerConsumerExample {
public static void main(String[] args) {
BlockingQueue<Integer> queue = new BlockingQueue<>(5);
// 生产者线程
Thread producer = new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
System.out.println("Producing: " + i);
queue.put(i);
Thread.sleep(100); // 模拟生产时间
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
// 消费者线程
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 10; i++) {
Integer item = queue.take();
System.out.println("Consuming: " + item);
Thread.sleep(150); // 模拟消费时间
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producer.start();
consumer.start();
}
}
put
方法:当队列满时,生产者线程会调用wait()
方法,进入等待状态,直到有空间可用时被唤醒。take
方法:当队列为空时,消费者线程会调用wait()
方法,进入等待状态,直到有元素可用时被唤醒。notifyAll
方法:在put
和take
方法中,分别在添加和移除元素后调用notifyAll()
,以唤醒其他等待的线程。这种实现方式是线程安全的,能够有效地处理多线程环境下的生产者-消费者问题。