java多线程BlockingDeque的三种线程安全正确退出方法

news2024/12/22 23:42:50

本文介绍两种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");

    }
}

在这里插入图片描述

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

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

相关文章

对顶堆模板!!【DS对顶堆】ABC281 E - Least Elements

我想的思路和正解是差不多的 就是滑动窗口&#xff0c;每过去一个用DS维护一下前k个元素和sum 本来想的是用优先队列维护前k个 然后想着multiset维护前k个&#xff0c;但是具体不知道怎么操作 这里用的是multiset维护对顶堆 关于对顶堆&#xff0c;我在寒假的时候总结过 …

【Java笔试强训】(1)

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f9be;&#x1f9be;&#x1f9be; 目录 一、选择题 二、编程题 &#x1f525;组队竞…

Github创建一个新仓库,关联本地数据并上传文件的图文步骤

工作中&#xff0c;我们经常会使用github来承享别人的代码果实&#xff0c;同时我们也会把自己的成果分享给别人&#xff0c;互相帮助。 今天的这篇图文教程非常重要&#xff0c;目标是使用Github来创建一个远程仓库&#xff0c;并和本地仓库对接&#xff0c;同时要做上传新内容…

初始Vue3【Vue3】

1.Vue3简介 2020年9月18日&#xff0c;Vue.js发布3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;海贼王&#xff09;耗时2年多、2600次提交、30个RFC、600次PR、99位贡献者github上的tags地址&#xff1a;https://github.com/vuejs/vue-next/releases/tag/v3.0.0 …

使用docker容器化部署mysql8.0.27,并更改其默认端口3306为3306全流程记录。

使用docker容器化部署mysql8.0.27,并更改其默认端口3306为3306全流程记录。 1.创建镜像 #查看镜像 docker images|grep mysql #搜索镜像 docker search mysql #拉取镜像 docker pull mysql&#xff1a;latest #运行镜像&#xff0c;--name 后的参数自己命名&#xff0c;我的数…

js逆向之rpc远程调用(你强任你强,我无视一切)

一、找到加密函数位置 二、在其下面注入ws服务 &#xff08;1)注入准备 资源>>替换>>随便选一个空文件夹 &#xff08;2&#xff09;进行注入 进行&#xff08;1&#xff09;操作后可直接编辑js代码了&#xff0c;做以下修改 (function() {var ws new WebSocket(…

ChatGPT实现代码生成

代码生成 就代码生成而言&#xff0c;ChatGPT 是一款卓越的工具&#xff0c;它为开发者提供强大的功能。ChatGPT 可以运用其出色的自然语言处理技术&#xff0c;深入理解和解释开发者的需求&#xff0c;快速生成适合的代码片段。对于那些繁琐的任务或者重复的代码&#xff0c;…

肝一肝设计模式【三】-- 原型模式

系列文章目录 肝一肝设计模式【一】-- 单例模式 传送门 肝一肝设计模式【二】-- 工厂模式 传送门 文章目录 系列文章目录前言一、什么是原型模式二、浅克隆三、深克隆写在最后 前言 前文中我们知道设计模式可以分为三大类&#xff1a;创建型模式、结构型模式、行为型模式。创…

Baumer工业相机堡盟相机如何使用偏振功能(偏振相机优点和行业应用)(C#)

项目场景&#xff1a; Baumer工业相机堡盟相机是一种高性能、高质量的工业相机&#xff0c;可用于各种应用场景&#xff0c;如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能&#xff0c;可以实时传输高分辨率图像。此外&#xff0…

tp6.1 bingher/ueditor(百度编辑器)(七牛、阿里OSS第三方云)详情图文教程(2023年第二版)

之前做过一版&#xff1a;tp6 bingher/ueditor(百度编辑器)(七牛、阿里OSS第三方云)详情图文教程_我是高手高手高高手的博客-CSDN博客 登录权限是Session&#xff0c;现在系统是Cookie加jwt的Token方式验证 一、修改验证登录权限 修改文件&#xff1a; vendor\bingher\uedito…

react native ios 添加启动页 xcode14 react-native-splash-screen

最近更新xcode&#xff0c;有些配置有些不同&#xff0c;网上查的方法都是过时的&#xff0c;导致配了一段时间卡在这里&#xff0c;最后访问官网才弄好了&#xff0c;所以以后解决问题的办法先看官网再查其他各路神仙的办法。 官网的步骤&#xff1a;https://github.com/crazy…

ChatGPT原理剖析

文章目录 ChatGPT常见误解1. 罐头回应2. 网络搜寻重组 ChatGPT真正做的事——文字接龙ChatGPT背后的关键技术——预训练&#xff08;Pre-train&#xff09;一般机器是怎样学习的&#xff1f; ChatGPT带来的研究问题1. 如何精准提出需求2. 如何更改错误3. 侦测AI生成的物件4. 不…

众人围剿,GPT-5招惹了谁

目录 千人呼吁暂停AI训练代表人物分析反对原因分析信息安全人身安全失业利益 总结 GPT-4 火爆全球&#xff0c;引发了人工智能大浪潮。过去的一个月&#xff0c;OpenAI、微软、谷歌加上百度不断释放王炸&#xff0c;所有人都相信&#xff0c;AI 的就是未来的生产力。俗话说&…

如何在本地搭建Maven环境并整合进IDEA中以及创建web工程?【2023最新版】

编译软件&#xff1a;IntelliJ IDEA 2019.2.4 x64 操作系统&#xff1a;win10 x64 位 家庭版 Maven版本&#xff1a;apache-maven-3.6.3 目录 一. 为什么要使用Maven&#xff1f;1.1 获取jar包1.2 添加jar包1.3 使用Maven便于解决jar包冲突及依赖问题 二. 什么是Maven?三. 如何…

Elasticsearch查询文档--常见API篇(附详细代码和案例图文)

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;在一家满意的公司实习。本篇文章将介绍Elasticsearch在Java中的几种API的使用&#xff0c;这块内容不作为面试中的重点。 如果文章有什么需要改进的地方还请大佬不吝赐教&#x1f44f;&#x1f4…

Linux Ansible任务控制(循环判断、处理程序、失败任务)

目录 Ansible的Loop循环 简单的Loop循环 数组列表方式的Loop循环 字典方式的Loop循环 基于外部变量的Loop循环 Ansible的When判断 通过魔法变量、事实变量作为条件 通过剧本执行结果的变量来作为条件 Ansible处理程序 Ansible处理失败任务 处理失败任务ignore_error…

语义分割学习笔记(二)转置卷积

目录 1.转置卷积Transposed Convolution概念 2.转置卷积操作步骤 3.转置卷积参数 4.实战案例 推荐课程&#xff1a;转置卷积&#xff08;transposed convolution&#xff09;_哔哩哔哩_bilibili 感谢霹雳吧啦Wz&#xff0c;真乃神人也。 1.转置卷积Transposed Convolutio…

分类预测 | MATLAB实现WOA-CNN鲸鱼算法优化卷积神经网络数据分类预测

分类预测 | MATLAB实现WOA-CNN-LSTM鲸鱼算法优化卷积长短期记忆网络数据分类预测 目录 分类预测 | MATLAB实现WOA-CNN-LSTM鲸鱼算法优化卷积长短期记忆网络数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现WOA-CNN多特征分类预测&#xff0c;多特…

SimpleCG库安装使用

SimpleCG库是一个简单的Windows图形库&#xff0c;对GDI及窗口和消息机制进行了简单封装&#xff0c;从而达到类似Turbo C图形库的调用方法&#xff0c;目的是为了初学C语言的同学能快速上手图形界面编程。使用对象包括所有初学C语言的同学&#xff0c;尤其是中学生&#xff0c…

PAT B1049

PAT B1049 题目 给定一个正数数列&#xff0c;我们可以从中截取任意的连续的几个数&#xff0c;称为片段。例如&#xff0c;给定数列 { 0.1, 0.2, 0.3, 0.4 }&#xff0c;我们有 (0.1) (0.1, 0.2) (0.1, 0.2, 0.3) (0.1, 0.2, 0.3, 0.4) (0.2) (0.2, 0.3) (0.2, 0.3, 0.4) (0…