Java中的阻塞队列有界和无界区别
在Java中,阻塞队列(Blocking Queue)是一个线程安全的队列,它能够在队列为空时使消费者线程阻塞,或者在队列满时使生产者线程阻塞。阻塞队列在并发编程中非常常见,特别是在生产者-消费者问题的场景中。
阻塞队列可以分为有界阻塞队列和无界阻塞队列。
1. 有界阻塞队列(Bounded Blocking Queue)
有界阻塞队列是指队列的大小是有限制的。当队列已满时,生产者线程会被阻塞,直到队列中有空间可以插入新元素为止。同样,当队列为空时,消费者线程会被阻塞,直到队列中有新元素可供消费。
使用场景:
- 任务队列:在有并发消费者时,队列大小有限制,以防止内存溢出。
- 流控:通过限制队列的大小来防止生产者过快地生成任务,导致资源消耗过大。
代码示例:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;public class BoundedBlockingQueueExample {public static void main(String[] args) throws InterruptedException {// 创建一个有界阻塞队列,容量为5BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(5);// 生产者线程Thread producer = new Thread(() -> {try {for (int i = 0; i < 10; i++) {queue.put(i); // 如果队列满了,生产者会被阻塞System.out.println("Produced: " + i);}} 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("Consumed: " + item);}} catch (InterruptedException e) {Thread.currentThread().interrupt();}});producer.start();consumer.start();producer.join();consumer.join();}
}
解释:
ArrayBlockingQueue
是一个典型的有界阻塞队列,容量为 5。- 生产者线程会在队列满时被阻塞,消费者线程会在队列为空时被阻塞。
2. 无界阻塞队列(Unbounded Blocking Queue)
无界阻塞队列是指队列的大小没有限制,理论上可以容纳无限个元素。在无界阻塞队列中,生产者不会因为队列已满而被阻塞,而是会一直将元素放入队列中;同样,消费者也不会因为队列为空而被阻塞(虽然通常会等待有新的元素可供消费)。
使用场景:
- 不需要流控:当生产者生成数据的速度远慢于消费者时,队列大小无所谓。
- 动态扩展:当队列的大小没有明确限制时,可以适应生产者和消费者之间不平衡的情况。
代码示例:
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.BlockingQueue;public class UnboundedBlockingQueueExample {public static void main(String[] args) throws InterruptedException {// 创建一个无界阻塞队列BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();// 生产者线程Thread producer = new Thread(() -> {try {for (int i = 0; i < 10; i++) {queue.put(i); // 不会被阻塞,因为队列是无界的System.out.println("Produced: " + i);}} 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("Consumed: " + item);}} catch (InterruptedException e) {Thread.currentThread().interrupt();}});producer.start();consumer.start();producer.join();consumer.join();}
}
解释:
LinkedBlockingQueue
是一个典型的无界阻塞队列。- 由于是无界的,生产者不会因为队列满而被阻塞,消费者会等到有新的元素可供消费。
有界与无界阻塞队列的比较
特性 | 有界阻塞队列 | 无界阻塞队列 |
---|---|---|
队列大小 | 有限 | 无限(理论上没有大小限制) |
生产者行为 | 队列满时,生产者会被阻塞 | 队列大小不受限制,生产者不会阻塞 |
消费者行为 | 队列空时,消费者会被阻塞 | 队列为空时,消费者会被阻塞 |
内存使用 | 队列大小受限,避免内存溢出 | 内存可能被用尽,造成资源消耗过大 |
典型应用场景 | 任务队列、流控、资源管理 | 数据传输、生产者消费者模型(当生产者慢于消费者时) |
总结:
- 有界阻塞队列适用于资源有限的情况,它能帮助限制队列的大小,防止内存溢出并进行流控。
- 无界阻塞队列适用于队列容量不受限制的情况,但要注意如果生产者速度过快,可能会导致系统资源消耗过大。
根据实际应用场景选择适合的阻塞队列类型。