《Java并发编程实战》课程笔记(十二)

news2024/12/19 11:07:20

CountDownLatch 和 CyclicBarrier:如何让多线程步调一致?

原始对账系统

  • 对账系统的业务简化后:
    • 首先用户通过在线商城下单,会生成电子订单,保存在订单库;
    • 之后物流会生成派送单给用户发货,派送单保存在派送单库。
    • 为了防止漏派送或者重复派送,对账系统每天还会校验是否存在异常订单。
  • 目前对账系统的处理逻辑是首先查询订单,然后查询派送单,之后对比订单和派送单,将差异写入差异库。
    在这里插入图片描述
  • 对账系统的核心代码如下,就是在一个单线程里面循环查询订单、派送单,然后执行对账,最后将写入差异库。
    while (存在未对账订单) {
    	// 查询未对账订单
    	pos = getPOrders();
    	// 查询派送单
    	dos = getDOrders();
    	// 执⾏对账操作
    	diff = check(pos, dos);
    	// 差异写⼊差异库
    	save(diff);
    }
    

利用并行优化对账系统

  • 对于串行化的系统,优化性能首先想到的是能否利用多线程并行处理。
    • 查询未对账订单 getPOrders() 和查询派送单 getDOrders() 是否可以并行处理呢?
    • 显然是可以的,因为这两个操作并没有先后顺序的依赖。
      while () {
      	// 查询未对账订单
      	Thread t1 = new Thread(() -> {
      		pos = getPOrders();
      	});
      	t1.start();
      	// 查询派送单
      	Thread t2 = new Thread(()->{
      		dos = getDOrders();
      	});
      	t2.start();
      	// 等待 t1、t2 结束
      	t1.join();
      	t2.join();
      	// 执⾏对账操作
      	diff = check(pos, dos);
      	// 差异写⼊差异库
      	save(diff);
      }
      

用 CountDownLatch 实现线程等待

  • while 循环里面每次都会创建新的线程,而创建线程可是个耗时的操作。所以最好是创建出来的线程能够循环利用,线程池就能解决这个问题。
    Executor executor = Executors.newFixedThreadPool(2);
    while (存在未对账订单) {
    	// 计数器初始化为 2
    	CountDownLatch latch = new CountDownLatch(2);
    	// 查询未对账订单
    	executor.execute(() -> {
    		pos = getPOrders();
    		latch.countDown();
    	});
    	// 查询派送单
    	executor.execute(()-> {
    		dos = getDOrders();
    		latch.countDown();
        });
    	// 等待两个查询操作结束
    	latch.await();
    	// 执⾏对账操作
    	diff = check(pos, dos);
    	// 差异写⼊差异库
    	save(diff);
    }
    
  • 我们将 getPOrders() 和 getDOrders() 这两个查询操作并行了,但这两个查询操作和对账操作 check()、save() 之间还是串行的。很显然,这两个查询操作和对账操作也是可以并行的,也就是说,在执行对账操作的时候,可以同时去执行下一轮的查询操作。
    • 针对对账这个项目,我设计了两个队列,并且两个队列的元素之间还有对应关系。
    • 订单查询操作将订单查询结果插入订单队列,派送单查询操作将派送单插入派送单队列,这两个队列的元素之间是有对应关系的。
    • 两个队列的好处是,对账操作可以每次从订单队列出一个元素,从派送单队列出一个元素,然后对这两个元素执行对账操作,这样数据一定不会乱掉。
      在这里插入图片描述
    • ⼀个线程 T1 执行订单的查询工作,一个线程 T2 执行派送单的查询工作,当线程 T1 和 T2 都各自生产完 1 条数据的时候,通知线程 T3 执行对账操作。
    • 线程 T1 和线程 T2 只有都生产完 1 条数据的时候,才能一起向下执行,也就是说,线程 T1 和线程 T2 要互相等待,步调要一致。
    • 同时当线程 T1和 T2 都生产完一条数据的时候,还要能够通知线程 T3 执行对账操作。

用 CyclicBarrier 实现线程同步

  • 我们首先创建了一个计数器初始值为 2 的 CyclicBarrier,你需要注意的是创建 CyclicBarrier 的时候,我们还传入了一个回调函数,当计数器减到 0 的时候,会调用这个回调函数。
    • 线程 T1 负责查询订单,当查出一条时,调用 barrier.await() 来将计数器减 1,同时等待计数器变成 0;
    • 线程 T2 负责查询派送单,当查出一条时,也调用 barrier.await() 来将计数器减 1,同时等待计数器变成 0;
    • 当 T1 和 T2 都调用 barrier.await() 的时候,计数器会减到 0,此时 T1 和 T2 就可以执行下⼀条语句了,同时会调用 barrier 的回调函数来执行对账操作。
    • CyclicBarrier 的计数器有自动重置的功能,当减到 0 的时候,会自动重置你设置的初始值。
      // 订单队列
      Vector<P> pos;
      // 派送单队列
      Vector<D> pos;
      // 执⾏回调的线程池
      Executor executor = Executors.newFixedThreadPool(1);
      final CyclicBarrier barrier = new CyclicBarrier(2, () -> { executor.execute(() -> check()); });
      
      void check() {
      	P p = pos.remove(0);
      	D d = dos.remove(0);
      	// 执⾏对账操作
      	diff = check(p, d);
      	// 差异写⼊差异库
      	save(diff);
      }
      
      void checkAll() {
      	// 循环查询订单库
      	Thread t1 = new Thread(() -> {
      		while (存在未对账订单) {
      			// 查询订单库
      			pos.add(getPOrders());
      			// 等待
      			barrier.await();
      		}
      	});
      	t1.start();
      	// 循环查询运单库
      	Thread T2 = new Thread(()->{
      		while(存在未对账订单){
      			// 查询运单库
      			dos.add(getDOrders());
      			// 等待
      			barrier.await();
      			}
      	});
      	T2.start();
      }
      

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

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

相关文章

软件测试面试怎样介绍自己的测试项目?会问到什么程度?

想知道面试时该怎样介绍测试项目&#xff1f;会问到什么程度&#xff1f;那就需要换位思考&#xff0c;思考HR在这个环节想知道什么。 HR在该环节普遍想获得的情报主要是下面这2个方面&#xff1a; 1&#xff09;应聘者的具体经验和技术能力&#xff0c; 2&#xff09;应聘者的…

【企业化部署】Tomcat部署及优化

文章目录 前言一、Tomcat 的概念1. Tomcat 核心组件1.1 什么是 servlet1.2 什么是 JSP 2. Tomcat 功能组件结构2.1 Container 结构分析 3. Tomcat 请求过程4. 配置文件4.1 安装目录4.2 conf 子目录 二、Tomcat 服务部署1. 下载并安装 JDK1.1 关闭防火墙&#xff0c;将安装 Tomc…

码垛机械臂工作站系统设计

码垛机械臂工作站系统设计 第一章 控制系统硬件设计1.1 引言1.2 控制系统总体方案1.3 控制系统硬件的选型1.3.1 可编程控制器的选型1.3.2 工业触摸屏的选型1.3.3 传感器的选型 1.4 硬件的接线与通讯1.4.1 可编程控制器的I/O分配与接线1.4.2 伺服电机驱动器的接线1.4.3 触摸屏与…

XML入库后空白字符丢失问题

最近项目上在做电子病历&#xff0c;使用的是第三方的电子病历组件&#xff0c;该病历组件是利用XML来组织数据的。界面上渲染出来的效果如下图&#xff1a; XML渲染后的界面 对应的后台数据&#xff08;已做简化处理&#xff09;是如下XML格式的&#xff0c;其中的空格部分是…

Windows 下配置Vitis HLS OpenCV仿真库(记录帖)

遇到的问题 我的配置&#xff1a; Vitis Vision 2022 opencv-4.4.0 vision Library 2022 Vitis HLS 2021.1 实测有BUG&#xff0c;编译好之后无法综合&#xff0c;别问我为什么知道 1. Download opencv_ffmpeg.dll 卡住 解决方法 打开 new_build 目录&#xff08;编译路径&…

从小白到大神之路之学习运维第33天——第三阶段——mysql数据库

第三阶段基础 时 间&#xff1a;2023年6月5日 参加人&#xff1a;全班人员 内 容&#xff1a; Mysql数据库 目录 前提环境配置&#xff1a; 一、CentOS 7 安装 MySQL 5.7 二、MySQL 操作示例&#xff1a; 三、MySQL 5.7远程登录 前提环境配置&#xff1a; 关闭防火…

微信如何批量添加好友?

现在营销中&#xff0c;微信已成为一种重要的沟通方式。微信目前是没有自动批量添加好友的功能&#xff0c;需要运营者一个一个手动去添加&#xff0c;这样太过于浪费时间&#xff0c;并且加频繁了还容易被封号&#xff0c;今天给大家介绍几种手动批量加好友的方式以及怎么借助…

人工智能和网络安全哪个好?一般人我还是劝你算了吧

人工智能门槛高&#xff0c;上限高 网络安全门槛低&#xff0c;下限低 但是以目前的行业内招聘需求来看网安缺hvv安服工具人和法学双修合规人&#xff0c;人工智能缺高端算法大牛。 一、从安全出发&#xff0c;然后去学习人工智能&#xff0c;最后走人工智能安全。 这个确实需…

Java网络通讯案例——即时通讯(控制台版)

一、需求分析 用户与用户之间1-1或1-n通讯 二、技术分析 &#xff08;一&#xff09;客户端 客户端的功能有两个&#xff1a;发消息和接消息发消息&#xff1a;使用Socket技术的流式输出&#xff0c;配合打印流封装发送。接信息&#xff1a;使用读取专用线程&#xff0c;搭配…

usmile笑容加新品发布,可视化定义电动牙刷未来发展路径?

历经20余年的发展&#xff0c;中国电动牙刷市场以外资品牌入华为肇始&#xff0c;到目前已经呈现出品牌林立、供给丰富&#xff0c;且国产品牌开始后来者居上的局面。 但近年来行业高速发展的势头似乎有所收敛&#xff0c;与此同时&#xff0c;市场还具备广阔的可拓展空间。数…

M.2 SSD接口详解

一、M.2简介 M.2接口是一种新的主机接口方案&#xff0c;可以兼容多种通信协议&#xff0c;如sata、PCIe、USB、HSIC、UART、SMBus等。 M.2接口是为超极本&#xff08;Ultrabook&#xff09;量身定做的新一代接口标准&#xff0c;以取代原来的mSATA接口。无论是更小巧的规格尺…

【Web服务应用】Tomcat部署

Tomcat部署 一、Tomcat简介二、tomcat组件2.1核心组件2.2Tomcat功能组件2.3Tomcat 请求过程 三、部署Tomcat服务3.1Tomcat虚拟主机配置 四、Tomcat多实例部署 一、Tomcat简介 一款 java 开发的开源的 Web 应用服务程序。 可以作为Web应用服务器&#xff0c;处理静态的Web页面&…

比别人更快,更优秀的测试方法!(持续更新)

目录 css selector 应用场景 场景&#xff1a;假设有100个商品要添加&#xff0c;但是没有全选按钮&#xff0c;怎么办&#xff1f; 模拟微信UserAgent设置 场景&#xff1a;模拟微信打开H5 VPN下如何抓包 场景&#xff1a;APP需要开启VPN代理才能正常访问&#xff0c;同时…

NEEPUSec CTF 2023 easymath

easymath 题目描述&#xff1a; from Crypto.Util.number import *flagbytes_to_long(bNeepu{xxx})N 738931348122338421499476261982330058997842307585754071200798137388701886017484620800095723028366934218646065252158059518352370641258869511690690571844077077623…

聊聊TCP协议的粘包、拆包以及http是如何解决的?

目录 一、粘包与拆包是什么&#xff1f; 二、粘包与拆包为什么发生&#xff1f; 三、遇到粘包、拆包怎么办&#xff1f; 解决方案1&#xff1a;固定数据大小 解决方案2&#xff1a;自定义请求协议 解决方案3&#xff1a;特殊字符结尾 四、HTTP如何解决粘包问题的&#xf…

Nginx踩坑记录(二) nginx: [warn] invalid value “TLSv1.3“ in /etc/nginx/nginx.conf:20

问题详情 &#xff08;通过指定配置文件的方式&#xff09;启动nginx&#xff0c;提示告警&#xff0c;nginx启动失败。 rootvultr:~# nginx -c /etc/nginx/conf/nginx.conf nginx: [warn] invalid value "TLSv1.3" in /etc/nginx/conf/conf.d/v2ray.conf:20问题原…

高校学生公寓数字化安全用电管理系统解决方案

摘要 本文针对高校学生公寓用电特点,从安全用电角度提出了一套集用电管理、计量、恶性负载智能识别控制、实时跟踪检测等功能于一体的数字化安全用电管理系统技术解决方案———学生公寓智能控电管理系统。 关键词:公寓恶性负载安全用电智能系统 0、引言 近年来,为了响应国…

chatgpt赋能python:Python后处理:优化你的SEO

Python后处理&#xff1a;优化你的SEO 在今天的数字世界中&#xff0c;SEO是任何成功的企业或网站的必要元素之一。搜索引擎优化不仅可以帮助你的网站排名更高&#xff0c;还可以影响你的流量和销售。因此&#xff0c;为了优化SEO表现&#xff0c;很多企业和网站都把目光投向了…

2个月过去了,面试至今0 offer,这是怎么了?

转眼已是6月初&#xff0c;求职招聘季也结束啦&#xff0c;如果没点真技术、真本事&#xff0c;不了解点职场套路&#xff0c;在今年行情下&#xff0c;找工作可是难上加难。 现在点开微博或者脉脉&#xff0c;只要搜索“招聘”&#xff0c;用“惨不忍睹”来形容也不为过。不少…

windows11安装docker desktop实现docker环境

简介 我们知道docker的安装一般我们是安装在linux系统上的&#xff0c;但是如果你的宿主机是windows&#xff0c;那么你还想装docker&#xff0c;那么就需要现在你的windows上装上虚拟机&#xff0c;虚拟机上装linux操作系统&#xff0c;然后在Linux操作系统上再去安装docker&…