CountDownLatch实战应用——实现异步多线程业务处理,异常情况回滚全部子线程

😊 @ 作者: 一恍过去
💖 @ 主页: https://blog.csdn.net/zhuocailing3390
🎊 @ 社区: Java技术栈交流
🎉 @ 主题: CountDownLatch实战应用——实现异步多线程业务处理,异常情况回滚全部子线程
⏱️ @ 创作时间: 2023年12月1日7

在这里插入图片描述

目录

  • 1、概述
  • 2、实现
  • 3、方法说明:
  • 4、代码实例

1、概述

CountDownLatch是一个同步器工具类,用来协调多个线程之间的同步,能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行,不可重置使用。

2、实现

使用一个计数器进行实现,计数器初始值为线程的数量,当每一个线程完成自己任务后,计数器的值就会减一,当计数器的值为0时,在CountDownLatch上等待的线程就可以恢复执行接下来的任务。

3、方法说明:

  • public void countDown():递减锁存器的计数,如果计数到达零,则释放所有等待的线程。如果当前计数大于零,则将计数减少.
  • public viod await() /boolean await(long timeout,TimeUnit unit) :使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。如果当前计数为零,则此方法立刻返回true值。当线程调用了CountDownLatch对象的该方法后,当前线程会被阻塞,直到下面的情况之一发生才会返回:
    • 如果计数到达零,则该方法返回true值。
    • 如果当前线程,在进入此方法时已经设置了该线程的中断状态;或者在等待时被中断,则抛出InterruptedException,并且清除当前线程的已中断状态。
    • 如果超出了指定的等待时间,则返回值为false。如果该时间小于等于零,则该方法根本不会等待。参数:timeout-要等待的最长时间、unit-timeout 参数的时间单位

4、代码实例

Controller:

@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {@Resourceprivate CountDownService countDownService;/*** CountDownLatch实现异步多线程不同业务处理,不同service,异常情况回滚全部子线程** @return*/   @GetMapping("/countDown/handleDataBack")public String countDownHandleDataBack() {countDownService.handleDataBack();return "success";}

Sevice:

@Service
@Slf4j
public class CountDownService {@Resourceprivate TestMapper testMapper;@Resourceprivate ApplicationContext applicationContext;/*** 主线程,同时调用多个个子线程进行业务处理,当其中一个子线程出现异常,则全部子线程进行回滚*/@Transactional(rollbackFor = Exception.class)public void handleDataBack() {AtomicBoolean errorTag = new AtomicBoolean(false);// 设置countDown大小,与异步执行的业务数量一样,比如2个CountDownLatch countDownLatch = new CountDownLatch(2);// 再创建一个CountDownLatch,大小固定为一,用于子线程相互等待,最后确定是否回滚CountDownLatch errorCountDown = new CountDownLatch(1);// 异步调用其他Service,执行业务处理CountDownService bean = applicationContext.getBean(CountDownService.class);bean.handleTestOne(countDownLatch, errorCountDown, errorTag);bean.handleTestTwo(countDownLatch, errorCountDown, errorTag);try {// 主线程阻塞countDownLatch.await();// 可以设置最大阻塞时间,防止线程一直挂起/*boolean await = countDownLatch.await(1, TimeUnit.SECONDS);if (!await) {// 超过时间子线程都还没有结束,直接都回滚errorTag.set(true);}*/log.info("继续执行主线程");// 继续执行后续的操作,比如insert、update等TestEntity entity = new TestEntity();entity.setId(new Random().nextInt(999999999));entity.setCount(1);entity.setCommodityCode("handleTestMain");entity.setMoney(new Random().nextInt(1000000));entity.setUserId("user-handleTestMain");testMapper.insert(entity);} catch (Exception e) {log.error("主线程业务执行异常");errorTag.set(true);} finally {// 主线程业务执行完成后,执行errorCountDown计时器减一,使得所有阻塞的子线程,继续执行进入到异常判断中errorCountDown.countDown();}// 如果出现异常if (errorTag.get()) {throw new RuntimeException("异步业务执行出现异常");}log.info("主线程执行完成");}/*** 子线程具体业务处理*/@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)@Asyncpublic void handleTestOne(CountDownLatch countDownLatch, CountDownLatch errorCountDown, AtomicBoolean errorTag) {log.info("开始执行handleTestOne线程");// 模拟业务耗时ThreadUtil.sleep(2000);try {// 执行数据库操作TestEntity entity = new TestEntity();entity.setId(new Random().nextInt(999999999));entity.setCount(1);entity.setCommodityCode("handleTestOne");entity.setMoney(new Random().nextInt(1000000));entity.setUserId("user-handleTestOne");testMapper.insert(entity);// 模拟出现异常int a = 1 / 0;} catch (Exception e) {errorTag.set(true);}// 子线程中,业务处理完成后,利用countDown的特性,计数器减一操作countDownLatch.countDown();// 子阻塞,直到其他子线程完成操作try {errorCountDown.await();} catch (Exception e) {errorTag.set(true);}log.info("handleTestOne-子线程执行完成");if (errorTag.get()) {// 抛出异常,回滚数据throw new RuntimeException("handleTestOne-子线程业务执行异常");}}/*** 子线程具体业务处理*/@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)@Asyncpublic void handleTestTwo(CountDownLatch countDownLatch, CountDownLatch errorCountDown, AtomicBoolean errorTag) {log.info("开始执行handleTestTwo线程");// 模拟业务耗时ThreadUtil.sleep(500);try {// 执行数据库操作TestEntity entity = new TestEntity();entity.setId(new Random().nextInt(999999999));entity.setCount(1);entity.setCommodityCode("handleTestTwo");entity.setMoney(new Random().nextInt(1000000));entity.setUserId("user-handleTestTwo");testMapper.insert(entity);} catch (Exception e) {errorTag.set(true);}// 子线程中,业务处理完成后,利用countDown的特性,计数器减一操作countDownLatch.countDown();// 子阻塞,直到其他子线程完成操作try {errorCountDown.await();} catch (Exception e) {errorTag.set(true);}log.info("handleTestTwo-子线程执行完成");if (errorTag.get()) {// 抛出异常,回滚数据throw new RuntimeException("handleTestTwo-子线程业务执行异常");}}
}

在这里插入图片描述

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

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

相关文章

H266/VVC编码标准介绍

视频编码标准 多样的视频应用催生了多种的视频编码方法。为了使编码后的码流能够在大范围内通用和规范,从20世纪80年代开始,国际组织就开始对视频编码建立国际标准。 什么是视频编码标准: 视频编码标准只规定了码流的语法语义和解码器&#…

Appium —— 初识移动APP自动化测试框架Appium

说到移动APP自动化测试,代表性的测试框架非Appium莫属,从今天开始我们将从APP结构解析、Appium框架学习、安卓/iOS自动化测试实战、自动遍历回归测试、自动化测试平台及持续集成,多个维度一起由浅入深的学废Appium 今天我们先来初步认识Appi…

【消息中间件】Rabbitmq的基本要素、生产和消费、发布和订阅

原文作者:我辈李想 版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、消息队列的基本要素1.队列:queue2.交换机:exchange3.事件:routing_key4.任务:task 二、生产消费模式1.安装pika2.模拟生产者进程3.模…

【HR培训】行为反馈复盘,走出舒适区--20231217

行为反馈复盘,走出舒适区–鱼缸会议 要点:在于建立平等、透明、敢说的反馈环境,不打断、不争论 鱼缸会议流程 导入——入缸——反馈——承诺——关闭 步骤1:导入 目的:平等、透明、敢说的反馈 人员:主…

maui中实现加载更多 RefreshView跟ListView(1)

效果如图: MainPage.xaml.cs: using System; using System.Collections.ObjectModel; using System.Threading.Tasks; using Microsoft.Maui.Controls; using Microsoft.Maui.Controls.Xaml; using System.ComponentModel; using System.Runtime.CompilerServices…

计算机网络基础——网线认识与制作,线缆类型、线序、端接标准及注意事项

一、引言 网线制作是网络基础知识中不可或缺的。网络传输过程中,网线的质量和制作方法都会直接影响传输的速度和稳定性。本文将详细介绍网线制作的基础知识、线缆类型、线序、端接标准及注意事项。希望通过本文,读者能够更好地了解和掌握网线制作的方法…

AMD 自适应和嵌入式产品技术日

概要 时间:2023年11月28日 地点:北京朝阳新云南皇冠假日酒店 主题内容:AMD自适应和嵌入式产品的更新,跨越 云、边、端的AI解决方案,赋能智能制造的机器视觉与机器人等热门话题。 注:本文重点关注FPGA&a…

ASP.NET MVC实战之权限拦截Authorize使用

1&#xff0c;具体的实现方法代码如下 public class CustomAuthorizeAttribute : FilterAttribute, IAuthorizationFilter{/// <summary>/// 如果需要验证权限的时候&#xff0c;就执行进来/// </summary>/// <param name"filterContext"></par…

Ubuntu系统入门指南:基础操作和使用

Ubuntu系统的基础操作和使用 一、引言二、安装Ubuntu系统三、Ubuntu系统的基础操作3.1、界面介绍3.2、应用程序的安装和卸载3.3、文件管理3.4、系统设置 四、Ubuntu系统的日常使用4.1、使用软件中心4.2、浏览器的使用和网络连接设置4.3、邮件客户端的配置和使用4.4、文件备份和…

HTML5+CSS3小实例:3D发光切换按钮效果

目录 一、运行效果 图片效果 二、项目概述 三、开发环境 四、实现步骤及代码 1.创建空文件夹 2.完成页面内容 3.完成css样式 五、项目总结 六、源码获取 一、运行效果 图片效果 二、项目概述 这个项目是一个演示3D发光切换按钮效果的网页。按钮由一个开关和一个指…

Linux之进程(四)(进程地址空间)

目录 一、程序地址空间 二、进程地址空间 1、概念 2、写时拷贝 3、为什么要有进程地址空间 四、总结 一、程序地址空间 我们先来看看下面这张图。这张图是我们在学习语言时就见到过的内存区域划分图。 下面我们在Linux下看一看内存区域是不是也是这么划分的。 可见在Li…

圣诞树绘制合集-python绘制

使用Python绘制迷人的圣诞树 引言 随着圣诞节的临近&#xff0c;我们都希望以各种方式庆祝这个欢乐的节日。作为一名编程爱好者&#xff0c;你有没有想过用Python来创造节日的气氛呢&#xff1f;在这篇文章中&#xff0c;我将向你展示如何用Python绘制几种不同风格的圣诞树&a…

索尼(ILCE-7M3)MP4文件只能播放前两分钟修复案例

索尼的ILCE-7M3是一款经典设备&#xff0c;其HEVC编码效果是比较不错的&#xff0c;因此受到很多专业人士的青睐。之前我们说过很多索尼摄像机断电生成RSV文件修复的案例&#xff0c;今天来讲一个特殊的&#xff0c;文件已经正常封装但仅能播放前两分钟多一点的画面。 故障文件…

详细教程 - 从零开发 鸿蒙harmonyOS应用 第四节 (鸿蒙Stage模型 登录页面 ArkTS版 推荐使用)

在鸿蒙OS中&#xff0c;Ability是应用程序提供的抽象功能&#xff0c;可以理解为一种功能。在应用程序中&#xff0c;一个页面即一种能力&#xff0c;如登录页面&#xff0c;即具有登录功能的能力。以下是对鸿蒙新建项目的登录代码功能的详细解读和工作流程的描述&#xff1a; …

C++入门篇

呀哈喽&#xff0c;我是结衣。 了解完C的发展历程&#xff0c;我们当然也要会用C啊。今天这篇博客就是来帮助我们来入门C的&#xff0c;当然要入门C当然也要先学会C语言啦。在我学习C的过程中我会一直把C博客更新下去的。 C关键字 我们都知道C语言是有32个关键字的&#xff0…

json JSON.parse()与JSON.stringify()

JSON.parse() 属于解析 JSON.parse()方法解析一个JSON字符串为ECMAScript值&#xff0c;返回解析后的值&#xff0c; JSON.parse({}); // -> {}JSON.parse([]); // -> []JSON.parse(1); // -> {}注意&#xff1a;JSON.parse()解析的JSON字符串不允许以逗…

Python-数据分析可视化实例图

Python-数据分析可视化实例图 一&#xff1a;3D纹理图 运行效果图&#xff1a; Python代码&#xff1a; import math from typing import Unionimport pyecharts.options as opts from pyecharts.charts import Surface3Ddef float_range(start: int, end: int, step: Union[…

分享66个Java源码总有一个是你想要的

分享66个Java源码总有一个是你想要的 学习知识费力气&#xff0c;收集整理更不易。 知识付费甚欢喜&#xff0c;为咱码农谋福利。 链接&#xff1a;https://pan.baidu.com/s/1hKlZJB3KrHcOuKWyV1xjKw?pwd6666 提取码&#xff1a;6666 项目名称 ava web个人网站项目 ea…

不是生活有意思,是你热爱生活它才有意思

明制汉服的设计 同样是一款很重工的外套 细节上也是做到了极致 顺毛毛呢面料 领口袖口拼接仿貂毛环保毛条 前胸欧根纱刺绣圆形布 袖子贴民族风珠片刺绣织带 门襟搭配金属子母扣&#xff0c;真盘扣设计 时尚经典&#xff0c;搭配马面裙孩子穿上 真的很有气质奢华富贵 …

程序人生15年人生感悟

计算机程序员并不是一件什么高大上的职业。而仅仅是一份普通的工作。就像医生能治病救人&#xff0c;我们能治蓝屏救程序&#xff0c;我们都在为这个世界默默的做出自己的贡献。刻意或无意宣扬某个职业高大上&#xff0c;其实质是对其它行业从业者的不公平。但是有些人却常常这…