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

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

在这里插入图片描述

目录

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

1、概述

CyclicBarrier是一个同步器工具类,用来协调多个线程之间的同步,通过await()进行阻塞,直到所有的线程都执行await()后,所有的线程再继续执行。

2、方法说明:

  • public viod await() /int await(long timeout,TimeUnit unit) :使当前线程一直等待,除非线程被中断或超出了指定的等待时间。
    当线程会被阻塞,直到下面的情况之一发生才会返回:
    • 如果每执行一次await() 计数加一,直到达到初始值。
    • 如果当前线程,在进入此方法时已经设置了该线程的中断状态;或者在等待时被中断,则抛出InterruptedException,并且清除当前线程的已中断状态。
    • 如果超出了指定的等待时间,则该方法根本不会再进行阻塞。

3、代码实例

Controller:

@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {@Resourceprivate CyclicService cyclicService;/*** CyclicBarrier实现异步多线程业务处理,不同service,异常情况回滚全部子线程** @return*/@ApiOperation(value = "测试CountDownLatch", notes = "测试")@ApiOperationSupport(order = 5)@GetMapping("/cyclic/handleDataBack")public String cyclicHandleDataBack() {cyclicService.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);// 设置CyclicBarrier大小,需要比实际子线程+1,业务主线程需要进行阻塞CyclicBarrier cyclicBarrier = new CyclicBarrier(2 + 1);// 再创建一个CountDownLatch,大小固定为一,用于子线程相互等待,最后确定是否回滚CountDownLatch errorCountDown = new CountDownLatch(1);// 异步调用其他Service,执行业务处理CyclicService bean = applicationContext.getBean(CyclicService.class);bean.handleTestOne(cyclicBarrier, errorCountDown, errorTag);bean.handleTestTwo(cyclicBarrier, errorCountDown, errorTag);try {// 主线程阻塞cyclicBarrier.await();// 可以设置最大阻塞时间,防止线程一直挂起,当子线程时间大于当前时间后会抛出TimeOut异常// cyclicBarrier.await(1, TimeUnit.SECONDS);// 继续执行后续的操作,比如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(CyclicBarrier cyclicBarrier, 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);}// 子线程中,业务处理完成后,利用cyclicBarrier的特性,计数器加一操作try {cyclicBarrier.await();} catch (Exception e) {errorTag.set(true);}// 子阻塞,直到其他子线程完成操作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(CyclicBarrier cyclicBarrier, 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);}// 子线程中,业务处理完成后,利用cyclicBarrier的特性,计数器加一操作try {cyclicBarrier.await();} catch (Exception e) {errorTag.set(true);}// 子阻塞,直到其他子线程完成操作try {errorCountDown.await();} catch (Exception e) {errorTag.set(true);}log.info("handleTestTwo-子线程执行完成");if (errorTag.get()) {// 抛出异常,回滚数据throw new RuntimeException("handleTestTwo-子线程业务执行异常");}}
}

在这里插入图片描述

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

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

相关文章

Linux笔记本电脑投屏到电视,用网页浏览器就能投屏到电视!

Linux系统的电脑如果要投屏到安卓电视屏幕上,可以使用投屏工具AirDroid Cast的网页版和TV版一起实现。 首先,在Linux系统的电脑里用chrome浏览器或edge浏览器打开网址webcast.airdroid.com。这个网址就是AirDroid Cast的网页版。你可以看到中间白色框框的…

Canal使用详解

Canal介绍 Canal是阿里巴巴开发的MySQL binlog增量订阅&消费组件,Canal是基于MySQL二进制日志的高性能数据同步系统。在阿里巴巴集团中被广泛使用,以提供可靠的低延迟增量数据管道。Canal Server能够解析MySQL Binlog并订阅数据更改,而C…

cilium原理之ebpf尾调用与trace

背景 在深入剖析cilium原理之前,有两个关于epbf的基础内容需要先详细介绍一下: 1. ebpf尾调用 尾调用类似于程序之间的相互跳转,但它的功能更加强大。 2. trace 虽然之前使用trace_printk输出日志,但这个函数不能多用&#x…

使用StableDiffusion进行图片Inpainting原理

论文链接:RePaint: Inpainting using Denoising Diffusion Probabilistic Models代码链接:RePaint Inpainting任务是指在任意一个二进制的掩码指定的图片区域上重新生成新的内容,且新生成的内容需要和周围内容保持协调。当前SOTA模型用单一类…

高级算法设计与分析(四) -- 贪心算法

系列文章目录 高级算法设计与分析(一) -- 算法引论 高级算法设计与分析(二) -- 递归与分治策略 高级算法设计与分析(三) -- 动态规划 高级算法设计与分析(四) -- 贪心算法 高级…

FATFS文件系统

文件系统是为了存储和管理数据,而在存储设备上建立的一种组织结构。 Windows常用的文件系统: 1、FAT12 2、FAT16 3、FAT32 4、exFAT 5、NTFS FAT:File Alloction Table 文件分配表 在小型的嵌入式存储设备大多…

Ubuntu 常用命令之 ping 命令用法介绍

📑Linux/Ubuntu 常用命令归类整理 ping命令是一种网络诊断工具,用于测试主机之间网络的连通性。它发送ICMP Echo Request消息到指定的网络主机,并等待接收ICMP Echo Reply。通过这种方式,我们可以知道两台主机之间的网络是否畅通…

pycharm修改项目文件夹名称

目录 1 修改项目文件夹名称 2 修改代码中的项目名称 1 修改项目文件夹名称 选中项目文件夹,右键,选择refactor-rename。 选择rename project: 然后输入新的项目名称。 此时进入资源管理器,修改项目文件夹的名字,完成…

IntelliJ IDEA 2023.3 新功能介绍

IntelliJ IDEA 2023.3 在众多领域进行了全面的改进,引入了许多令人期待的功能和增强体验。以下是该版本的一些关键亮点: IntelliJ IDEA mac版下载 macappbox.com/a/intellij-idea-for-mac.html 1. AI Assistant 的全面推出 IntelliJ IDEA 2023.3 中&am…

ES-mapping

类似数据库中的表结构定义,主要作用如下 定义Index下的字段名( Field Name) 定义字段的类型,比如数值型、字符串型、布尔型等定义倒排索引相关的配置,比如是否索引、记录 position 等 index_options 用于控制倒排索记录的内容,有如…

钓鱼与木马实践(仅供参考不可实践)

声明:内容仅供学习,请勿违法使用,违者后果自负 一.部署云服务器 购买一台云服务器,Windows( 中文 )版本即可 华为云官网:https://www.huaweicloud.com/ 登录后进入控制台购买完成后远程登录云服务器 二.部署WEB运行…

QQ群发邮件的技巧?QQ邮箱邮件群发怎么发?

QQ群发邮件怎么设置?QQ邮件群发必备利器有哪些? QQ群发邮件,作为当下最流行的通讯方式之一,已经被广大网友所熟知。但是,要想真正掌握QQ群发邮件的技巧,却不是一件容易的事情。下面,就让蜂邮ED…

【Linux笔记】系统信息

🍎个人博客:个人主页 🏆个人专栏:Linux学习 ⛳️ 功不唐捐,玉汝于成 目录 前言 命令 1. uname - 显示系统信息 2. hostname - 显示或设置系统主机名 3. top - 显示系统资源使用情况 4. df - 显示磁盘空间使用情…

Qt通用属性工具:随心定义,随时可见(一)

一、开胃菜&#xff0c;没图我说个DIAO 先不BB&#xff0c;给大家上个效果图展示下&#xff1a; 上图我们也没干啥&#xff0c;几行代码&#xff1a; #include "widget.h" #include <QApplication> #include <QObject> #include "QtPropertyEdit…

pmp到底是什么?

一、PMP是什么 PMP 是项目管理的入门级证书&#xff0c;全称是项目管理专业人士资格认证&#xff0c;由美国项目管理协会&#xff08;PMI&#xff09;举办的&#xff0c;从1999 年到现在已经有20多年发展历史了。 顾名思义&#xff0c;PMP考试就是一场评估应试者是否具备专业…

React学习计划-React16--React基础(五)脚手架创建项目、todoList案例、配置代理、消息订阅与发布

一、使用脚手架create-react-app创建项目 react脚手架 xxx脚手架&#xff1a;用来帮助程序员快速创建一个基于xxx库的模板项目 包含了所有需要的配置&#xff08;语法检查、jsx编译、devServe…&#xff09;下载好了所有相关的依赖可以直接运行一个简单的效果 react提供了一个…

红队打靶练习:DIGITALWORLD.LOCAL: MERCY V2

目录 信息收集 1、arp 2、netdiscover 3、nmap 4、nikto 5、whatweb 6、总结 目录探测 1、gobuster 2、dirsearch WEB enum4linux枚举工具 smbclient工具 knock工具 CMS 文件包含漏洞 Tomcat 提权 系统信息收集 本地提权 get root 信息收集 1、arp ┌──…

【设计模式】命令模式

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、什么是命令模式&#xff1f; 二、命令模式的优点和应用场景 三、命令模式的要素和实现 3.1 命令 3.2 具体命令 3.3 接受者 …

Github 2023-12-23 开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2023-12-23统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目6C项目2C项目1Jupyter Notebook项目1HTML项目1Go项目1非开发语言项目1 免费API集体清单 创建周期…

VGGNet

目录 一、VGGNet介绍 1、VGG块 2、VGG架构 3、LeNet, AlexNet和VGGNet对比 4、总结 二、代码实现 1、定义VGG卷积块 2、VGG网络 3、训练模型 4、总结 一、VGGNet介绍 VGGNet&#xff08;Visual Geometry Group Network&#xff09;是一种深度卷积神经网络&#xff0c;…