【Java并发】【LinkedBlockingQueue】适合初学体质的LinkedBlockingQueue入门

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD

🔥 2025本人正在沉淀中… 博客更新速度++

👍 欢迎点赞、收藏、关注,跟上我的更新节奏

📚欢迎订阅专栏,专栏名《在2B工作中寻求并发是否搞错了什么》

前言

你是否在线程池工具类里看到过它的身影?

public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());

你是否会好奇LinkedBlockingQueue是啥呢?

没有关系,小手手点上关注,跟上主播的节奏。

什么是LinkedBlockingQueue?

LinkedBlockingQueue 是一个基于链表的线程安全阻塞队列,常用于生产者-消费者模式。

数据结构

  • 基于单向链表实现,队列头尾分别通过 head 和 last 指针维护。
  • 默认容量为 Integer.MAX_VALUE(近似无界队列),但可手动指定固定容量。

线程安全

  • 使用两把锁分离设计(入队锁 putLock 和出队锁 takeLock),提高并发性能。
  • 通过 ReentrantLock 和 Condition 实现阻塞(队列空时阻塞消费者,队列满时阻塞生产者)。

阻塞操作

  • put():队列满时阻塞生产者线程。
  • take():队列空时阻塞消费者线程。
  • 非阻塞方法:offer()(失败返回 false)、poll()(失败返回 null)

简单说说,和我们之前说的ArrayBlokcingQueue的区别:

特性LinkedBlockingQueueArrayBlockingQueue
底层结构链表数组
默认容量Integer.MAX_VALUE(无界)必须显式指定
锁机制双锁分离(更高并发)单锁控制
内存占用动态扩展(链表节点开销)预分配连续内存

简单使用LinkedBlockingQueue

因为我们的LinkedBlockingQueue也是实现了BlockingQueue的接口,所以下面的代码例子,会有这些方法。

在这里插入图片描述

构造方法

首先从构造方法说起吧,LinkedBlockingQueue有3个构造方法:

// 没有传任何参数,默认容量大小为Integer.MAX_VALUE
public LinkedBlockingQueue();// 容量大小为入参
public LinkedBlockingQueue(int capacity)// 容量大小为Integer.MAX_VALUE,集合中初始化元素为c
public LinkedBlockingQueue(Collection<? extends E> c)

添加元素入队操作

add(E e)方法:简单粗暴,非阻塞添加元素,队列满了的话直接抛IllegalStateException异常。

public static void main(String[] args) {BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);queue.add("A");queue.add("B"); // Exception in thread "main" java.lang.IllegalStateException: Queue full
}

offer(E e)方法:非阻塞添加元素,成功返回boolean,添加成功为true,添加失败为false

public static void main(String[] args) {BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);boolean result = queue.offer("A"); // trueSystem.out.println(result);result = queue.offer("B"); // falseSystem.out.println(result);
}

offer(E e, long timeout, TimeUnit unit)方法: 向队列添加元素。如果队列满了,就阻塞线程,等待一段时间,一段时间过后队列还是满的话,意味添加元素失败返回false,否则返回true。

public static void main(String[] args) throws InterruptedException {BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);boolean result = queue.offer("A", 1, TimeUnit.SECONDS); // trueSystem.out.println(result);result = queue.offer("B", 1, TimeUnit.SECONDS); // falseSystem.out.println(result);
}

但如果我们这样等待一会的话,执行结果就会不一样:

public static void main(String[] args) throws InterruptedException {BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);boolean result = queue.offer("A", 1, TimeUnit.SECONDS); // trueSystem.out.println(result);// 启动另一个生产者线程new Thread(() -> {Boolean res;try {res = queue.offer("B", 2, TimeUnit.SECONDS); // 队列满了,阻塞2s等待} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(res);       // true}).start();// 移除队列中的元素queue.poll();
}

put(E e)方法: 阻塞线程,直到队列不为空或中断者线程。

public static void main(String[] args) throws InterruptedException {BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);queue.put("A");queue.put("B"); // 队列已满,线程阻塞在这
}

移除元素出队操作

remove()方法:如果队列为空,直接抛出NoSuchElementException异常。

public static void main(String[] args) {BlockingQueue<Object> queue = new LinkedBlockingQueue<>(1);queue.remove(); // Exception in thread "main" java.util.NoSuchElementException
}

poll()方法:非阻塞获取队列头元素,如果队列为空,直接返回null。

public static void main(String[] args) {BlockingQueue<String> queue = new LinkedBlockingQueue<>(1);String poll = queue.poll();System.out.println(poll); // null(队列中没有元素)queue.offer("A");      // 向队列中添加元素poll= queue.poll();System.out.println(poll); // A
}

poll(long timeout, TimeUnit unit)方法:阻塞一段时间获取队列中的元素,如果超过时间了,就队列还是为空,就返回null。

public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue = new LinkedBlockingQueue<>(1);// 创建一个线程,3s后生产1个元素到队列中new Thread(() -> {try {Thread.sleep(2000);queue.offer("A");} catch (InterruptedException e) {e.printStackTrace();}}).start();// 消费者,阻塞5s获取元素String poll= queue.poll(5 , TimeUnit.SECONDS);System.out.println(poll); // A
}

take()方法:阻塞线程获取队列中的元素,直到队列不为空,或者被其他线程中断,抛出异常停止。

public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue = new LinkedBlockingQueue<>(1);// 创建一个消费者线程,获取队列中的元素Thread consumerThread = new Thread(() -> {try {String take = queue.take();     // 在这个案例中,线程会被一直阻塞到这,直到被中断System.out.println("消费者线程获取到元素:" + take);} catch (InterruptedException e) {System.out.println("线程者线程被中断了");}});consumerThread.start();// 隔3s后,中断消费者线程TimeUnit.SECONDS.sleep(1);consumerThread.interrupt();
}输出结果:
线程者线程被中断了

检查队列中的元素

element() 方法: 返回队列头的元素,但是如果队列为空,element方法会抛出NoSuchElementException异常。

public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);queue.offer("A");queue.offer("B");System.out.println(queue.element());    // Aqueue.poll();   // 头元素出队System.out.println(queue.element());    // B
}// 异常的情况
public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);String element = queue.element();   // Exception in thread "main" java.util.NoSuchElementException
}

peek() 方法:和element()方法差不多,返回队列头的元素,如果队列为空,会返回null

public static void main(String[] args) throws InterruptedException {BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);String element = queue.peek();System.out.println(element);    // null
}

后话

这就结束了?没有的,宝贝,没有的。

这里只是简答的使用,小手手点上关注,主播下一篇,直接开始看LinkedBlockingQueue源码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/80381.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python在AI虚拟教学视频开发中的核心技术与前景展望

Python在AI虚拟教学视频开发中的核心技术与前景展望 一、引言&#xff1a;AI虚拟教学的技术革新 随着教育数字化转型加速&#xff0c;AI虚拟教学视频凭借个性化、沉浸式体验成为教育科技的新风口。Python以其强大的多模态处理能力、丰富的开源生态和跨领域兼容性&#xff0c;成…

shadcn/radix-ui的tooltip高度定制arrow位置

尝试了半天&#xff0c;后来发现&#xff0c;不支持。。。。。就是不支持 那箭头只能居中 改side和align都没用&#xff0c;下面有在线实例 https://codesandbox.io/p/sandbox/radix-ui-slider-forked-zgn7hj?file%2Fsrc%2FApp.tsx%3A69%2C21 但是呢&#xff0c; 第一如果…

自动清空 maven 项目临时文件,vue 的 node_modules 文件

echo off setlocal enabledelayedexpansion :: vue 的 node_modules 太大 :: maven 打包后的 target 文件也很大&#xff0c; :: 有些项目日志文件也很大&#xff0c;导致磁盘空间不足了&#xff0c; :: 所以写了个脚本&#xff0c;只要配置一下各项目目录&#xff0c; :: 双击…

[Mybatis-plus]

简介 MyBatis-Plus &#xff08;简称 MP&#xff09;是一个 MyBatis的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变。Mybatis-plus官网地址 注意&#xff0c;在引入了mybatis-plus之后&#xff0c;不要再额外引入mybatis和mybatis-spring&#xff0c;避免因为版本…

管理100个小程序-很难吗

20公里的徒步-真难 群里的伙伴发起了一场天目山20公里徒步的活动&#xff0c;想着14公里都轻松拿捏了&#xff0c;思考了30秒后&#xff0c;就借着春风带着老婆孩子就出发了。一开始溪流清澈见底&#xff0c;小桥流水没有人家&#xff1b;青山郁郁葱葱&#xff0c;枯藤老树没有…

大模型工业化元年:GPT-5开启通用AI新纪元,中国技术如何破局?

过去一周&#xff0c;AI领域的焦点无疑是OpenAI发布的GPT-5预览版&#xff0c;以及全球大模型技术从实验室迈向工业化的关键转折。这场变革不仅标志着通用人工智能&#xff08;AGI&#xff09;的进一步逼近&#xff0c;更掀起了全球产业链的竞争与反思。本文将从技术突破、产业…

软考【网络工程师】2023年5月上午题答案解析

1、固态硬盘的存储介质是()。 A 光盘 B 闪存 C 软盘 D 磁盘 答案是 B。 固态硬盘(Solid State Drive),简称 SSD,是用固态电子存储芯片阵列制成的硬盘,其存储介质是闪存(Flash Memory)。闪存具有非易失性,即在断电后仍能保留存储的数据,且读写速度快、抗震性强、能…

【速写】钩子与计算图

文章目录 前向钩子反向钩子的输入反向钩子的输出 前向钩子 下面是一个测试用的计算图的网络&#xff0c;这里因为模型是自定义的缘故&#xff0c;可以直接把前向钩子注册在模型类里面&#xff0c;这样会更加方便一些。其实像以前BERT之类的last_hidden_state以及pool_output之…

高级电影感户外街拍人像摄影后期Lr调色教程,手机滤镜PS+Lightroom预设下载!

调色介绍 高级电影感户外街拍人像摄影后期 Lr 调色&#xff0c;是运用 Adobe Lightroom 软件&#xff0c;对户外街拍的人像照片进行后期处理&#xff0c;以塑造出具有电影质感的独特视觉效果。此调色过程借助 Lr 丰富的工具与功能&#xff0c;从色彩、光影、对比度等多维度着手…

16.QT-Qt窗口-菜单栏|创建菜单栏|添加菜单|创建菜单项|添加分割线|添加快捷键|子菜单|图标|内存泄漏(C++)

Qt窗⼝是通过QMainWindow类来实现的。 QMainWindow是⼀个为⽤⼾提供主窗⼝程序的类&#xff0c;继承⾃QWidget类&#xff0c;并且提供了⼀个预定义的布局。QMainWindow包含⼀个菜单栏&#xff08;menu bar&#xff09;、多个⼯具栏(tool bars)、多个浮动窗⼝&#xff08;铆接部…

【kafka初学】启动执行命令

接上篇&#xff0c;启动&#xff1a;开两个cdm窗口 注意放的文件不要太深或者中文&#xff0c;会报命令行太长的错误 启动zookeeper bin\windows\zookeeper-server-start.bat config\zookeeper.properties2. 启动kafka-serve bin\windows\kafka-server-start.bat config\serv…

利用 Claw Cloud Run 免费应用部署前端网页

一、注册 使用注册180天的github账户注册Claw Cloud账户&#xff0c;可获得每月5$的免费配额官网链接 - https://run.claw.cloud/ &#xff08;ps&#xff1a;直接github账号登录应该就不用写了吧&#xff09; 二、创建应用 打开App Launchpad 点击Create AppCPU选0.1即可&a…

豆瓣图书数据采集与可视化分析(三)- 豆瓣图书数据统计分析

文章目录 前言一、数据读取与保存1. 读取清洗后数据2. 保存数据到CSV文件3. 保存数据到MySQL数据库 二、不同分类统计分析1. 不同分类的图书数量统计分析2. 不同分类的平均评分统计分析3. 不同分类的平均评价人数统计分析4. 不同分类的平均价格统计分析5. 分类综合分析 三、不同…

网络原理 - 3(UDP 协议)

目录 协议 应用层 xml json protobuffer 传输层 端口号&#xff08;Port&#xff09; UDP 协议 UDP 协议端格式 完&#xff01; 协议 网络通信中&#xff0c;协议是一个非常重要的概念。我们前面在网络原理中&#xff0c;就已经介绍了&#xff0c;为了统一各方网络&…

Java Agent 注入 WebSocket 篇

Agent 如果要对其进行Agent注入的编写&#xff0c;需要先理解三个名字premain&#xff0c;agentmain&#xff0c;Instrumentation premain方法在 JVM 启动阶段调用&#xff0c;一般维持权限的时候不会使用 agentmain方法在 JVM 运行时调用 常用的 Instrumentation实例为代理…

【深度强化学习 DRL 快速实践】近端策略优化 (PPO)

PPO&#xff08;2017&#xff0c;OpenAI&#xff09;核心改进点 Proximal Policy Optimization (PPO)&#xff1a;一种基于信赖域优化的强化学习算法&#xff0c;旨在克服传统策略梯度方法在更新时不稳定的问题&#xff0c;采用简单易实现的目标函数来保证学习过程的稳定性 解决…

笔试强训:Day2

一、字符串中找出连续最长的数字串(双指针) 字符串中找出连续最长的数字串_牛客题霸_牛客网 #include <iostream> #include <string> #include <cctype> using namespace std;int main() {//双指针string str;cin>>str;int nstr.size();int begin-1,l…

MySQL 详解之 InnoDB:核心特性深度剖析 (ACID, 事务, 锁, 外键, 崩溃恢复)

在 MySQL 的世界里,存储引擎是数据库管理系统的核心组成部分,它负责数据的存储和提取。MySQL 支持多种存储引擎,如 MyISAM, Memory, CSV 等,但自 MySQL 5.5 版本以来,InnoDB 成为了默认的存储引擎,也是绝大多数应用场景的首选。 为什么 InnoDB 如此重要并被广泛采用?因…

Java中正则表达式使用方法

1. 正则表达式概述 正则表达式&#xff08;Regular Expression&#xff0c;简称 Regex&#xff09;是一种用于匹配字符串的模式工具。在 Java 中&#xff0c;正则表达式通过 java.util.regex 包实现&#xff0c;主要涉及以下两个类&#xff1a; Pattern&#xff1a;表示一个编…

使用浏览器的Clipboard API实现前端复制copy功能

在前端开发中&#xff0c;复制文本到剪贴板的功能通常使用浏览器的 Clipboard API 实现。比如 navigator.clipboard.writeText 方法。以下是一个简单的案例&#xff0c;展示如何使用 Clipboard API 实现复制文本的功能。 基本用法 首先&#xff0c;你需要创建一个按钮&#x…