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

Java 并发包 LinkedBlockingQueue 详解

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

并发大师发布于 2026/3/26更新于 2026/7/749 浏览
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. 九、总结
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 基于人工蜂群非确定性双向规划的无人机路径规划(Matlab 实现)
  • 基于快速选择算法:数组第 K 大元素与最小 K 个数
  • ESLint 核心原理与实战配置指南
  • 本地运行大模型工具:Ollama 安装与使用详解
  • Python 将 CSV 数据导入 Neo4j 的实现方法
  • GitHub Copilot 兼容 OpenAI/Anthropic API 的代理工具 copilot-api
  • LeetCode 141:环形链表检测的经典解法
  • Rust 与 WebAssembly 深度实战:浏览器与 Node.js 的高性能融合
  • AI 产品经理入门指南:《AI 赋能》书籍推荐与学习路径
  • WebGIS 开发实战:WKT 转 GeoJSON 技巧与 Leaflet 加载
  • C++ 数组模拟单双向链表实现与优化
  • Ubuntu 24.04 安装 NVIDIA Container Toolkit 配置 Docker GPU 加速
  • MySQL 数据库核心操作:创建、修改、备份与恢复实战
  • Go 语言实现字符串全排列算法(含源码)
  • ADBC 动态 SQL 开发中如何降低 SQL 注入风险
  • Obsidian Text Generator 插件:AI 文本生成与配置指南
  • 宇树 G1 机器人开发入门:有线与无线连接配置指南
  • 汇川 RobotLab 软件常规操作指南
  • Jenkins 实战:多仓库集成、自动构建与公网远程部署
  • 鸿蒙应用开发:使用 Swiper 组件实现复杂轮播图

相关免费在线工具

  • 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