JUC:堵塞队列BlockingQueue和同步SynchronousQueue

BlockingQueue

堵塞队列的特点:

  • 写入:如果队列满了,就必须堵塞等待
  • 取出:如果队列是空的,必须堵塞等待生产

堵塞队列的应用场景:线程池
在这里插入图片描述
在这里插入图片描述继承关系图

在这里插入图片描述

四组API

方式抛出异常有返回值,不抛出异常堵塞等待超时等待
添加addofferputoffer(obj,int,TimeUnit)
移除removepolltakepoll(int,TimeUnit)
首个元素elementpeek
  1. 抛出异常
ArrayBlockingQueue<Object> objectArrayBlockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(objectArrayBlockingQueue.add("a"));
System.out.println(objectArrayBlockingQueue.add("b"));
System.out.println(objectArrayBlockingQueue.add("c"));
System.out.println(objectArrayBlockingQueue.add("d"));
System.out.println(objectArrayBlockingQueue.element());
System.out.println("==================================");
System.out.println(objectArrayBlockingQueue.remove());
System.out.println(objectArrayBlockingQueue.remove());
System.out.println(objectArrayBlockingQueue.remove());
true
true
true
a
==================================
a
b
c

如果超过capacity或者取元素时队列为空,抛出异常:

Exception in thread "main" java.lang.IllegalStateException: Queue full
  1. 有返回值,不抛出异常
ArrayBlockingQueue<Object> objectArrayBlockingQueue = new ArrayBlockingQueue<>(3);
System.out.println(objectArrayBlockingQueue.offer("a"));
System.out.println(objectArrayBlockingQueue.offer("b"));
System.out.println(objectArrayBlockingQueue.offer("c"));

System.out.println(objectArrayBlockingQueue.peek());
System.out.println("==================================");
System.out.println(objectArrayBlockingQueue.poll());
System.out.println(objectArrayBlockingQueue.poll());
System.out.println(objectArrayBlockingQueue.poll());
true
true
true
a
==================================
a
b
c

当从空队列取值/超过容量:
在这里插入图片描述

  1. 堵塞等待
ArrayBlockingQueue<Object> objectArrayBlockingQueue = new ArrayBlockingQueue<>(3);
objectArrayBlockingQueue.put("a");
objectArrayBlockingQueue.put("b");
objectArrayBlockingQueue.put("c");
System.out.println("放入三个元素");
System.out.println("================");
System.out.println(objectArrayBlockingQueue.take());
System.out.println(objectArrayBlockingQueue.take());
System.out.println(objectArrayBlockingQueue.take());
System.out.println(objectArrayBlockingQueue.take());
System.out.println("结束");

如果取出元素时队列为空/超过队列容量,程序等待:
在这里插入图片描述

  1. 超时等待
 ArrayBlockingQueue blockingQueue = new ArrayBlockingQueue<>(3);
 blockingQueue.offer("a");
 blockingQueue.offer("b");
 blockingQueue.offer("c");
  blockingQueue.offer("d",2,TimeUnit.SECONDS); // 等待超过2秒就退出
 System.out.println("===============");
 System.out.println(blockingQueue.poll());
 System.out.println(blockingQueue.poll());
 System.out.println(blockingQueue.poll());
blockingQueue.poll(2,TimeUnit.SECONDS);

SynchronousQueue

SynchronousQueue类实现了BlockingQueue接口。SynchronousQueue是一个内部只能包含一个元素的队列。插入元素到队列的线程被阻塞,直到另一个线程从队列中获取了队列中存储的元素。同样,如果线程尝试获取元素并且当前不存在任何元素,则该线程将被阻塞,直到线程将元素插入队列。

/**
 * 同步队列
 * 和其他的BlockingQueue 不一样, SynchronousQueue 不存储元素
 * put了一个元素,必须从里面先take取出来,否则不能在put进去值!
 */
public class SynchronousQueueDemo {
    public static void main(String[] args) {
        BlockingQueue<String> blockingQueue = new SynchronousQueue<>(); // 同步队
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName()+" put 1");
                blockingQueue.put("1");
                System.out.println(Thread.currentThread().getName()+" put 2");
                blockingQueue.put("2");
                System.out.println(Thread.currentThread().getName()+" put 3");
                blockingQueue.put("3");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"T1").start();
        new Thread(()->{
            try {
              TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+"=>"+blockingQueue.take());
               TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+"=>"+blockingQueue.take());
              TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName()+"=>"+blockingQueue.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"T2").start();
    }
}
T1 put 1
T2=>1
T1 put 2
T2=>2
T1 put 3
T2=>3
<think> 我们正在讨论的是Java JUC中的BlockingQueue。根据用户的问题,他想要了解BlockingQueue的使用方法、特性以及实现类。 根据之前的引用,我们可以整理出以下信息: 一、BlockingQueue概述 BlockingQueue是一个支持两个附加操作的队列: 1. 当队列为空时,从队列中获取元素的操作将被阻塞,直到队列中有元素。 2. 当队列满时,向队列中添加元素的操作将被阻塞,直到队列中有空位。 二、BlockingQueue的核心方法 根据引用[4],BlockingQueue提供了一些方法,这些方法可以分为四组: 1. 抛出异常的方法: add(e): 添加元素,如果队列满则抛出IllegalStateException remove(): 移除并返回队头元素,如果队列空则抛出NoSuchElementException element(): 返回队头元素(不移除),如果队列空则抛出NoSuchElementException 2. 返回特殊值的方法(推荐使用): offer(e): 添加元素,成功返回true,失败返回false poll(): 移除并返回队头元素,队列空则返回null peek(): 返回队头元素(不移除),队列空则返回null 3. 阻塞的方法: put(e): 添加元素,如果队列满则阻塞直到有空间 take(): 移除并返回队头元素,如果队列空则阻塞直到有元素 4. 超时的方法: offer(e, time, unit): 在指定的时间内尝试添加元素,成功返回true,超时返回false poll(time, unit): 在指定的时间内尝试移除并返回队头元素,成功返回元素,超时返回null 三、BlockingQueue的特性 - 线程安全:所有实现类都是线程安全的,适用于生产者-消费者模型。 - 容量可选:可以是有界队列(如ArrayBlockingQueue)或无界队列(如LinkedBlockingQueue,默认容量为Integer.MAX_VALUE)。 四、常用实现类(根据引用[2]引用[3]) 1. ArrayBlockingQueue: 基于数组的有界阻塞队列,按FIFO排序。 2. LinkedBlockingQueue: 基于链表的阻塞队列,按FIFO排序。默认无界(但通常指定容量以避免资源耗尽),吞吐量通常高于ArrayBlockingQueue。 3. PriorityBlockingQueue: 支持优先级的无界阻塞队列。元素按自然顺序或Comparator排序。 4. DelayQueue: 基于PriorityQueue的无界阻塞队列,只有延迟期满的元素才能被取出。元素必须实现Delayed接口。 5. SynchronousQueue: 一种不存储元素的阻塞队列。每个插入操作必须等待另一个线程的移除操作,反之亦然。适用于传递性设计。 五、使用示例 引用[1]给出了一个简单的示例: ```java BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1024); queue.put("1"); String string = queue.take(); ``` 六、应用场景 生产者-消费者模型:BlockingQueue简化了多线程编程,生产者线程向队列放入数据,消费者线程从队列取出数据,无需手动同步。 七、注意事项 - 无界队列可能导致内存耗尽,因此建议在生产环境中使用有界队列。 - 当队列满或空时,阻塞操作可能会被中断,需要处理InterruptedException。 现在,我们整理回答结构如下: 1. BlockingQueue概述 2. 核心方法分类 3. 主要特性 4. 常用实现类及特点 5. 使用示例 6. 应用场景 7. 注意事项 然后生成相关问题。 注意:引用标识应放在引用内容的后面,如:[^1] </think> ### Java JUC `BlockingQueue` 详解 #### 一、核心特性与设计思想 `BlockingQueue` 是 JUC 包中解决**生产者-消费者问题**的核心工具,本质是线程安全的阻塞队列: 1. **自动阻塞机制** - 队列为空时:消费者线程自动阻塞,直到数据到达[^4] - 队列满时:生产者线程自动阻塞,直到空位出现[^4] $$ \text{阻塞状态} = \begin{cases} \text{生产者: } & \text{当 } size = capacity \\ \text{消费者: } & \text{当 } size = 0 \end{cases} $$ 2. **线程安全保证** 所有实现类内置锁条件变量,无需手动同步[^4] ```java // 生产者无需关心唤醒逻辑 queue.put(data); // 消费者无需关心等待逻辑 Data data = queue.take(); ``` #### 二、核心操作方法 | **方法类型** | 方法签名 | 行为说明 | |--------------------|----------------------------------|-----------------------------------| | **阻塞操作** | `void put(E e)` | 队列满时阻塞生产者[^4] | | | `E take()` | 队列空时阻塞消费者[^4] | | **限时阻塞** | `boolean offer(E e, long timeout, TimeUnit unit)` | 超时插入失败返回false | | | `E poll(long timeout, TimeUnit unit)` | 超时获取失败返回null | | **非阻塞操作** | `boolean offer(E e)` | 队列满立即返回false[^3] | | | `E poll()` | 队列空立即返回null[^3] | | **检查操作** | `E peek()` | 查看队首元素不移除 | #### 三、关键实现类对比 根据引用[2][^2]引用[3][^3]整理: | **实现类** | **数据结构** | **边界** | **排序规则** | **适用场景** | |------------------------|---------------|-------------|------------|----------------------------------| | `ArrayBlockingQueue` | 数组 | **有界** | FIFO | 固定资源池(如连接池) | | `LinkedBlockingQueue` | 链表 | 可选有界/无界 | FIFO | 高吞吐生产者-消费者(默认无界) | | `PriorityBlockingQueue`| 二叉堆 | **无界** | 优先级排序 | 任务调度(急诊分诊系统) | | `DelayQueue` | 优先级堆 | **无界** | 延迟时间排序| 定时任务调度[^1] | | `SynchronousQueue` | 无容器 | 虚拟容量1 | 无 | 线程间直接传递(线程池工作队列) | #### 四、典型使用场景 1. **生产者-消费者模型** ```java // 生产者线程 class Producer implements Runnable { private BlockingQueue<String> queue; public void run() { queue.put("Data_" + System.nanoTime()); // 自动阻塞 } } // 消费者线程 class Consumer implements Runnable { public void run() { String data = queue.take(); // 自动阻塞 process(data); } } ``` 2. **线程池任务队列** ```java ExecutorService pool = new ThreadPoolExecutor( 4, 4, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1000) // 有界队列防OOM ); ``` 3. **延迟任务调度(DelayQueue)** ```java class DelayedTask implements Delayed { long executeTime; public long getDelay(TimeUnit unit) { return unit.convert(executeTime - System.nanoTime(), NANOSECONDS); } } DelayQueue<DelayedTask> delayQueue = new DelayQueue<>(); ``` #### 五、性能优化要点 1. **队列容量选择** - 计算密集型:小队列(CPU核心数+1)减少上下文切换 - IO密集型:大队列(1000+)应对任务堆积 2. **公平性设置(ArrayBlockingQueue)** ```java // 避免线程饥饿(降低吞吐量) BlockingQueue fairQueue = new ArrayBlockingQueue(1000, true); ``` 3. **优先级策略** ```java // 急诊系统:危重病人优先处理 PriorityBlockingQueue<Patient> queue = new PriorityBlockingQueue<>( 11, (a,b) -> b.getUrgencyLevel() - a.getUrgencyLevel() ); ``` #### 六、注意事项 1. **资源耗尽风险** 无界队列(如`LinkedBlockingQueue`)可能导致 OOM,建议设定容量上限[^3] 2. **线程中断处理** 所有阻塞方法响应`InterruptedException`,需妥善处理中断: ```java try { queue.put(data); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 恢复中断状态 } ``` 3. **对象序列化** `BlockingQueue`实现类均未实现`Serializable`接口,不可直接网络传输 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值