跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

Java 并发包 LinkedBlockingQueue 详解

Java 并发包中基于链表实现的阻塞队列 LinkedBlockingQueue。介绍其双锁机制、内部数据结构(哨兵节点)、核心方法(put/take/offer/poll)及线程安全原理。对比了与 ArrayBlockingQueue 和 ConcurrentLinkedQueue 的差异,并指出适用场景为生产者 - 消费者模型及线程池任务队列,同时提醒注意无界队列的内存风险。

并发大师发布于 2026/3/26更新于 2026/9/268 浏览
Java 并发包 LinkedBlockingQueue 详解

一、概述

LinkedBlockingQueue 是 Java 并发包(java.util.concurrent)中基于链表实现的阻塞队列,支持可选容量限制(默认无界),通过 双锁机制(ReentrantLock)和 条件变量(Condition)实现线程安全。其核心设计目标是高吞吐量和生产者 - 消费者模型的高效协作。

关键特性
  1. 线程安全:通过分离的 putLock(入队锁)和 takeLock(出队锁)实现并发控制,减少锁竞争。
  2. 阻塞操作:put() 和 take() 方法在队列满或空时自动阻塞,支持超时等待。
  3. FIFO 顺序:严格遵循先进先出原则。
  4. 可选容量:构造时可指定最大容量(有界),默认无界(Integer.MAX_VALUE)。
  5. 弱一致性迭代器:遍历时可能看到部分更新,但不会抛出 ConcurrentModificationException。

二、内部数据结构

1. 节点类 Node<E>
static class Node<E> {
    E item; // 存储元素
    Node<E> next; // 指向下一个节点
    Node(E x) { item = x; }
}
  • 链表结构:通过 head(头节点)和 last(尾节点)维护队列顺序。
  • 哨兵节点:初始化时 head 和 last 均指向一个 item=null 的哨兵节点,简化边界处理。
2. 核心属性
属性作用
capacity队列最大容量(默认 Integer.MAX_VALUE)
count当前元素数量(AtomicInteger 保证原子性)
putLock/takeLock入队和出队操作的独占锁
notEmpty/notFull条件变量,分别用于队列空和队列满时的线程阻塞与唤醒

三、核心方法与实现原理

1. 入队操作
put(E e)
public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    int c = -1;
    Node<E> node = new Node<>(e);
    final ReentrantLock putLock = this.putLock;
    final AtomicInteger count = this.count;
    putLock.lockInterruptibly(); // 获取入队锁
    try {
        while (count.get() == capacity) {
            notFull.await(); // 队列满时阻塞
        }
        enqueue(node); // 入队操作
        c = count.getAndIncrement();
        if (c + 1 < capacity) notFull.signal(); // 唤醒其他生产者线程
    } finally {
        putLock.unlock();
    }
    if (c == 0) signalNotEmpty(); // 若队列之前为空,唤醒消费者线程
}
  • 阻塞逻辑:队列满时调用 notFull.await(),释放锁并等待。
  • 唤醒机制:入队成功后,若队列未满,通过 notFull.signal() 唤醒其他生产者线程。
offer(E e)
public boolean offer(E e) {
    if (e == null) throw new NullPointerException();
    final AtomicInteger count = this.count;
    if (count.get() == capacity) return false; // 非阻塞,直接返回失败
    int c = -1;
    Node<E> node = new Node<>(e);
    final ReentrantLock putLock = this.putLock;
    putLock.lock();
    try {
        if (count.get() < capacity) {
            enqueue(node);
            c = count.getAndIncrement();
            if (c + 1 < capacity) notFull.signal();
        }
    } finally {
        putLock.unlock();
    }
    if (c == 0) signalNotEmpty();
    return c >= 0;
}
  • 非阻塞特性:队列满时立即返回 false,不阻塞线程。

2. 出队操作
take()
public E take() throws InterruptedException {
    E x;
    int c = -1;
    final AtomicInteger count = this.count;
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lockInterruptibly(); // 获取出队锁
    try {
        while (count.get() == 0) {
            notEmpty.await(); // 队列空时阻塞
        }
        x = dequeue(); // 出队操作
        c = count.getAndDecrement();
        if (c > 1) notEmpty.signal(); // 唤醒其他消费者线程
    } finally {
        takeLock.unlock();
    }
    if (c == capacity) signalNotFull(); // 若队列之前满,唤醒生产者线程
    return x;
}
  • 阻塞逻辑:队列空时调用 notEmpty.await(),释放锁并等待。
  • 唤醒机制:出队成功后,若队列非空,通过 notEmpty.signal() 唤醒其他消费者线程。
poll()
public E poll() {
    final AtomicInteger count = this.count;
    if (count.get() == 0) return null; // 非阻塞,直接返回 null
    E x = null;
    int c = -1;
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lock();
    try {
        if (count.get() > 0) {
            x = dequeue();
            c = count.getAndDecrement();
            if (c > 1) notEmpty.signal();
        }
    } finally {
        takeLock.unlock();
    }
    if (c == capacity) signalNotFull();
    return x;
}
  • 非阻塞特性:队列空时立即返回 null,不阻塞线程。

四、线程安全与锁机制

1. 双锁分离
  • putLock:控制入队操作,允许多个生产者并发插入。
  • takeLock:控制出队操作,允许多个消费者并发移除。
  • 优势:减少锁竞争,提升吞吐量(相比单锁的 ArrayBlockingQueue)。
2. 条件变量
  • notEmpty:队列空时,消费者线程在此条件上等待。
  • notFull:队列满时,生产者线程在此条件上等待。
  • 唤醒策略:插入或移除元素后,通过 signal() 或 signalAll() 唤醒等待线程。

五、适用场景

  1. 生产者 - 消费者模型:平衡生产者和消费者的处理速度,避免资源浪费。
  2. 线程池任务队列:如 ThreadPoolExecutor 默认使用 LinkedBlockingQueue 作为任务缓冲区。
  3. 数据流水线处理:在多阶段数据处理中传递数据。
  4. 限流场景:通过设置容量限制防止系统过载。

六、与其他队列的对比

特性LinkedBlockingQueueArrayBlockingQueueConcurrentLinkedQueue
线程安全机制双锁分离单锁(ReentrantLock)CAS + 自旋
容量可选有界(默认无界)必须有界无界
性能高并发下吞吐量高低并发下延迟低读多写少场景更优
适用场景生产者 - 消费者、任务队列固定容量缓冲区高并发无锁队列

七、注意事项

  1. 内存风险:默认无界队列可能导致内存溢出(OOM),建议生产环境指定容量。
  2. 中断处理:阻塞方法(如 put()/take())会响应中断,需捕获 InterruptedException 并处理中断状态。
  3. 性能调优:高并发场景下,合理设置队列容量和线程池参数(如 corePoolSize、maximumPoolSize)。

八、源码设计细节

  1. 哨兵节点:初始化时 head 和 last 均指向空节点,简化插入和删除逻辑。
  2. 弱一致性迭代器:遍历时基于当前快照,允许并发修改但可能遗漏新元素。
  3. 内存管理:节点通过 new 分配,依赖 GC 回收,避免手动内存管理开销。

九、总结

LinkedBlockingQueue 是 Java 并发编程中高性能阻塞队列的典范,通过双锁分离和条件变量机制,在保证线程安全的同时最大化吞吐量。适用于生产者 - 消费者模型、线程池任务队列等场景,但需注意无界队列的内存风险。理解其底层实现(如双锁、条件变量)有助于在实际工程中合理应用。

目录

  1. 一、概述
  2. 关键特性
  3. 二、内部数据结构
  4. 1. 节点类 Node<E>
  5. 2. 核心属性
  6. 三、核心方法与实现原理
  7. 1. 入队操作
  8. put(E e)
  9. offer(E e)
  10. 2. 出队操作
  11. take()
  12. poll()
  13. 四、线程安全与锁机制
  14. 1. 双锁分离
  15. 2. 条件变量
  16. 五、适用场景
  17. 六、与其他队列的对比
  18. 七、注意事项
  19. 八、源码设计细节
  20. 九、总结

更多推荐文章

查看全部
  • C++ 多态机制详解:概念、实现与原理
  • JDK 安装与环境配置完整指南
  • Python+Agent 入门实战:搭建可复用 AI 智能体
  • Ward 服务器监控工具部署与 cpolar 远程访问配置
  • LangChain 聊天模型多场景实战:从固定角色到合规客服
  • 解决 IDEA 运行 Maven 时出现的 JAVA_TOOL_OPTIONS 编码警告
  • 通义万相 2.1 模型升级解析与应用调优实践
  • Python pandas 数据分析入门与实战
  • 互联网大厂 Android 面试题大全与核心知识点解析
  • GitHub 访问加速方法:Hosts 配置与 SwitchHosts 使用
  • OpenClaw:从认知到执行的行动型 AI 框架解析
  • Faster Whisper v1.7 日语视频本地自动翻译 SRT 字幕生成与 AMD 显卡支持教程
  • Python 分布式追踪实战:SkyWalking 埋点接入指南
  • 使用 DeepFace 与 OpenCV 实现实时情绪分析
  • 基于 Leaflet Trackplayer 的 WebGIS 高速轨迹可视化实战
  • Java 后端转 Web3 实战路线图
  • AIGC 时代:为何 AI 文本检测已成为刚需?
  • Python + AI Agent 智能体:从原理到实战,构建自主决策的 AI 助手
  • MCP 工具速成:npx vs. uvx 全流程安装指南
  • Supabase 全栈开发实战:从云服务到本地部署

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online