Java实现阻塞队列的多线程示例与解析

Java Q&A Hub 使用 GPT-4o-mini 回答

问题:

Java面试题之多线程 用Java实现阻塞队列

回答:

在Java中,阻塞队列是一种支持在队列为空时等待取出元素的队列,或者在队列满时等待插入元素的队列。Java的标准库中已经提供了java.util.concurrent包下的BlockingQueue接口及其实现类(如ArrayBlockingQueueLinkedBlockingQueue等),但我们可以自己实现一个简单的阻塞队列来加深理解。

下面是一个简单的阻塞队列的实现,使用了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();
    }
}

说明

  1. put方法:当队列满时,生产者线程会调用wait()方法,进入等待状态,直到有空间可用时被唤醒。
  2. take方法:当队列为空时,消费者线程会调用wait()方法,进入等待状态,直到有元素可用时被唤醒。
  3. notifyAll方法:在puttake方法中,分别在添加和移除元素后调用notifyAll(),以唤醒其他等待的线程。

这种实现方式是线程安全的,能够有效地处理多线程环境下的生产者-消费者问题。