java多线程BlockingDeque的三种线程安全正确退出方法
本文介绍两种BlockingDeque在多线程任务处理时正确结束的方法
一般最开始简单的多线程处理任务过程
- 把总任务放入BlockingDeque
- 创建多个线程,每个线程内逻辑时,判断BlockingDeque任务是否处理完,处理完退出,还有任务就BlockingDeque.take()取任务处理
- 主线程join等待多线程处理完,收尾处理完成任务。
最开始版本代码,10个任务,3个线程来处理
package org.example;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;public class Main3 {public static void main(String[] args){System.out.println("start");BlockingDeque<Integer> task = new LinkedBlockingDeque<>();for (int i = 0; i < 10; i++) {task.add(i);}List<Thread> workers = new ArrayList<>();for (int i = 0; i < 3; i++) {Thread worker = new Thread(()->{while (true) {Integer data = null;try {if (task.size()==0) {System.out.println(Thread.currentThread().getName() +" quit");break;}
// Thread.sleep(100); // 默认任务耗时data = task.take();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName() +" do "+ data);}});workers.add(worker);worker.start();}for (Thread worker: workers) {try {worker.join();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("job done");}
}
运行之后,感觉非常好,完美实现逻辑
但是当把上面的任务数加到200,线程数加到30,上面线程sleep的注释打开,再次运行,就会发现主进程最后会被一直卡着不结束,说明多线程没有正确判断任务结束,线程不安全
上面的子线程内的size()等于0到下面的BlockingDeque.take()取任务这段之间的代码,这段不是线程安全的
让线程正确判断任务结束,而且要线程安全的三种方法,推荐第二种,兼顾效率和兼容正确性
- 判断任务结束这段代码加synchronized约束起来,实现线程安全(太慢)
- 给总任务task内,加入和线程相同数量的停止标志marker
- 使用BlockingDeque.poll(超时时间) + 异常数据检查(需要检查异常数据)
使用synchronized约束
package org.example;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;public class Main {public static void main(String[] args) {System.out.println("start");BlockingDeque<Integer> task = new LinkedBlockingDeque<>();for (int i = 0; i < 20; i++) {task.add(i);}List<Thread> workers = new ArrayList<>();for (int i = 0; i < 3; i++) {Thread worker = new Thread(()->{while (true) {Integer data = null;synchronized (task) {if (task.size() ==0) {System.out.println(Thread.currentThread().getName() +" quit");break;}try {data = task.take();} catch (InterruptedException e) {throw new RuntimeException(e);}}try {Thread.sleep(300);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName() +" do "+ data);}});workers.add(worker);worker.start();}for (Thread worker: workers) {try {worker.join();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("job done");}
}
总任务添加stop marker停止标志
package org.example;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;public class Main2 {public static void main(String[] args){System.out.println("start");BlockingDeque<Integer> task = new LinkedBlockingDeque<>();for (int i = 0; i < 20; i++) {task.add(i);}List<Thread> workers = new ArrayList<>();for (int i = 0; i < 3; i++) task.add(99);for (int i = 0; i < 3; i++) {Thread worker = new Thread(()->{while (true) {Integer data = null;try {data = task.take();if (data == 99) {System.out.println(Thread.currentThread().getName() +" quit");break;}} catch (InterruptedException e) {throw new RuntimeException(e);}try {Thread.sleep(300);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName() +" do "+ data);}});workers.add(worker);worker.start();}for (Thread worker: workers) {try {worker.join();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("job done");}
}
使用BlockingDeque.poll(超时时间),避免了take的永久性等待问题,但是会取到null值,要加判断处理
package org.example;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;public class Main4 {public static void main(String[] args){System.out.println("start");BlockingDeque<Integer> task = new LinkedBlockingDeque<>();for (int i = 0; i < 200; i++) {task.add(i);}List<Thread> workers = new ArrayList<>();for (int i = 0; i < 30; i++) {Thread worker = new Thread(()->{while (true) {Integer data = null;try {if (task.size()==0) {System.out.println(Thread.currentThread().getName() +" quit");break;}Thread.sleep(100); // 默认任务耗时data = task.poll(1000, TimeUnit.MILLISECONDS);if (data == null) {System.out.println(Thread.currentThread().getName() +" get null");continue;}} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName() +" do "+ data);}});workers.add(worker);worker.start();}for (Thread worker: workers) {try {worker.join();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("job done");}
}
相关文章:

java多线程BlockingDeque的三种线程安全正确退出方法
本文介绍两种BlockingDeque在多线程任务处理时正确结束的方法 一般最开始简单的多线程处理任务过程 把总任务放入BlockingDeque创建多个线程,每个线程内逻辑时,判断BlockingDeque任务是否处理完,处理完退出,还有任务就BlockingDe…...

从STM32F407到AT32F407(一)
雅特力公司的MCU有着性能超群,价格优越的巨大优势,缺点是相关资料少一些,我们可以充分利用ST的现有资源来开发它。 我用雅特力的STM32F437开发板,使用原子 stm32f407的开发板自带程序,测试串口程序,原设定…...

【数据结构】顺序表和链表基本实现(含全代码)
文章目录 一、什么是线性表1. 什么是顺序表动态开辟空间和数组的问题解释LeetCode-exercise 2. 什么是链表2.1链表的分类2.2常用的链表结构及区别2.3无头单向非循环链表的实现2.4带头双向循环链表的实现2.5循序表和链表的区别LeetCode-exercise 3. 快慢指针LeetCode-exercise 一…...

CMake : Linux 搭建开发 - g++、gdb
目录 1、环境搭建 1.1 编译器 GCC,调试器 GDB 1.2 CMake 2、G 编译 2.1 编译过程 编译预处理 *.i 编译 *.s 汇编 *.o 链接 bin 2.2 G 参数 -g -O[n] -l、-L -I -Wall、-w -o -D -fpic 3、GDB 调试器 3.1 调试命令参数 4、CMake 4.1 含义 4.2…...

大数据实战 --- 美团外卖平台数据分析
目录 开发环境 数据描述 功能需求 数据准备 数据分析 RDD操作 Spark SQL操作 创建Hbase数据表 创建外部表 统计查询 开发环境 HadoopHiveSparkHBase 启动Hadoop:start-all.sh 启动zookeeper:zkServer.sh start 启动Hive: nohup …...

三大本土化战略支点,大陆集团扩大中国市场生态合作「朋友圈」
“在中国,大陆集团已经走过30余年的发展与耕耘历程,并在过去10年间投资了超过30亿欧元。中国市场也成为了我们重要的‘增长引擎’与‘定海神针’。未来,我们将继续深耕中国这个技术导向的市场。”4月19日上海车展上,大陆集团首席执…...

为什么停更ROS2机器人课程-2023-
机器人工匠阿杰肺腑之言: 我放弃了ROS2课程 真正的危机不是同行竞争,比如教育从业者相互竞争不会催生ChatGPT…… 技术变革的突破式发展通常是新势力带来的而非传统行业的升级改革。 2013年也就是10年前在当时主流视频网站开启分享: 比如 …...

【SpringCloud常见面试题】
SpringCloud常见面试题 1.微服务篇1.1.SpringCloud常见组件有哪些?1.2.Nacos的服务注册表结构是怎样的?1.3.Nacos如何支撑阿里内部数十万服务注册压力?1.4.Nacos如何避免并发读写冲突问题?1.5.Nacos与Eureka的区别有哪些ÿ…...

ChatGPT+智能家居在AWE引热议 OpenCPU成家电产业智能化降本提速引擎
作为家电行业的风向标和全球三大消费电子展之一,4月27日-30日,以“智科技、创未来”为主题的AWE 2023在上海新国际博览中心举行,本届展会展现了科技、场景等创新成果,为我们揭示家电与消费电子的发展方向。今年展馆规模扩大至14个…...

拷贝构造函数和运算符重载
文章目录 拷贝构造函数特点分析拷贝构造函数情景 赋值运算符重载运算符重载operator<运算符重载 赋值运算符前置和后置重载 拷贝构造函数 在创建对象的时候,是不是存在一种函数,使得能创建一个于已经存在的对象一模一样的新对象,那么接下…...

本周热门chatGPT之AutoGPT-AgentGPT,可以实现完全自主实现任务,附部署使用教程
AutoGPT 是一个实验性的开源应用程序,它由GPT-4驱动,但有别于ChatGPT的是, 这与ChatGPT的底层语言模型一致。 AutoGPT 的定位是将LLM的"思想"串联起来,自主地实现你设定的任何目标。 简单的说,你只用提出…...
Mysql 优化LEFT JOIN语句
1.首先说一下个人对LEFT JOIN 语句的看法,原先我是没注意到LEFT JOIN 会影响到性能的,因为我平时在项目开发中,是比较经常见到很多个关联表的语句的。 2.阿里巴巴手册说过,连接表的语句最好不超过3次,但是我碰到的项目…...
全栈成长-python学习笔记之数据类型
python数据类型 数字类型 类型类型转换整型 intint() 字符串类型转换 浮点型保留整数 int(3.14)3 int(3.94)3浮点型 floatfloat() #####字符串类型 类型类型转换字符串 strstr() 将其他数据类型转为字符串 布尔类型与空类型 布尔类型 类型类型转换布尔型 boolbool()将其他…...
面试|兴盛优选数据分析岗
1.离职原因、离职时间点 2.上一份工作所在的部门、小组、小组人员数、小组内的分工 3.个人负责的目标,具体是哪方面的成本 4.为了降低专员成本,做了哪些方面的工作 偏向于机制、分析方法、思维,当下主要是对于部分高收入专员收入不合理的情况…...
Redis(08)主从复制master-slave replication
文章目录 redis主从复制一. 配置文件的方式设置1. 主节点配置:2. 从节点1配置:3. 从节点2配置: 二. 命令的方式设置1. 创建服务2. 设置主从节点3. 测试 三. 从节点升级为主节点四. 查看主从关系 redis主从复制 Redis主从复制是将一个Redis实例的数据复制到多个Redis实例&#…...

被chatGPT割了一块钱韭菜
大家好,才是真的好。 chatGPT热度一直上升,让我萌生了一个胆大而创新的想法, 把chatGPT嵌入到Notes客户机中来玩。 考虑到我已经下载了一个chatGPT的Notes应用(请见《ChatGPT APIs for HCL DOMINO》),想着…...

vue3+ts+pinia+vite一次性全搞懂
vue3tspiniavite项目 一:新建一个vue3ts的项目二:安装一些依赖三:pinia介绍、安装、使用介绍pinia页面使用pinia修改pinia中的值 四:typescript的使用类型初识枚举 一:新建一个vue3ts的项目 前提是所处vue环境为vue3&…...

Apache安装与基本配置
1. 下载apache 地址:www.apache.org/download.cgi,选择“files for microsoft windows”→点击”ApacheHaus”→点击”Apache2.4 VC17”,选择x64/x86,点击右边download下面的图标。 2. 安装apache (1)把…...

哈夫曼树【北邮机试】
一、哈夫曼树 机试考察的最多的就是WPL,是围绕其变式展开考察。 哈夫曼树的构建是不断选取集合中最小的两个根节点进行合并,而且在合并过程中排序也会发生变化,因此最好使用优先队列来维护单调性,方便排序和合并。 核心代码如下…...

thinkphp:数值(保留小数点后N位,四舍五入,左侧补零,格式化货币,取整,生成随机数,数字与字母进行转换)
一、保留小数点后N位/类似四舍五入(以保留小数点后三位为准) number_format()函数:第一个参数为要格式化的数字,第二个参数为保留的小数位数 方法一: public function test() {$num 12.56789; // 待格式化的数字$r…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...

elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...