当前位置: 首页 > news >正文

【Java多线程】4——特定场景解决办法

4 特定场景解决方法

⭐⭐⭐⭐⭐⭐
Github主页👉https://github.com/A-BigTree
笔记仓库👉https://github.com/A-BigTree/tree-learning-notes
个人主页👉https://www.abigtree.top
⭐⭐⭐⭐⭐⭐


如果可以,麻烦各位看官顺手点个star~😊

如果文章对你有所帮助,可以点赞👍收藏⭐支持一下博主~😆


文章目录

  • 4 特定场景解决方法
    • 4.1 `CountDownLatch`
      • 实例
    • 4.2 `CyclicBarrier`
      • 实例
    • 4.3 `Semaphore`
      • 4.3.1 常规方式使用
      • 4.3.2 引入超时机制
      • 4.3.3 应用场景举例
    • 4.4 `Fork Join`
      • 4.4.1 介绍
      • 4.4.2 API介绍
        • `RescursiveTask`
        • `ForkJoinTask`
      • 4.4.3 案例
        • 需求
        • 代码

4.1 CountDownLatch

效果:指定一个操作步骤数量,在各个子线程中,每完成一个任务就给步骤数量 - 1;在步骤数量减到0之前,CountDownLatch 可以帮我们把最后一步操作抑制住(阻塞),让最后一步操作一直等到步骤被减到 0 的时候执行。

实例

有六名同学在值日,班长负责锁门。班长必须确保所有同学都离开教室再锁门。

// 声明一个变量,用来保存同学的数量
int stuNum = 6;// 创建CountDownLatch对象
CountDownLatch countDownLatch = new CountDownLatch(stuNum);// 创建和同学数量相等的线程
for (int i = 0; i < stuNum; i++) {String num = String.valueOf(i + 1);new Thread(()->{// 完成一次操作System.out.println(Thread.currentThread().getName() + " " + num + "号同学离开教室");// 让countDownLatch管理的数量-1countDownLatch.countDown();}).start();}// 让countDownLatch负责将最后一步操作抑制住
countDownLatch.await();System.out.println("班长锁门");

4.2 CyclicBarrier

支持多线程在执行各自任务的时候,到达某个状态点就等待,等所有线程都到达这个状态点再继续执行后步骤。

实例

public class DemoO19CyclicBarrierTest {private static List<List<String>> matrix = new ArrayList<>();static {matrix.add(Arrays.asList("normal","special","end"));matrix.add(Arrays.asList("normal","normal","special","end"));matrix.add(Arrays.asList("normal","normal","normal","special","end"));}public static void main(String[] args) {// 1.创建CyclicBarrier对象CyclicBarrier barrier = new CyclicBarrier(3);// 2.创建3个线程分别执行各自的任务new Thread(()->{try {List<String> list = matrix.get(0);for (String value : list) {TimeUnit.SECONDS.sleep(1);System.out.println(Thread.currentThread().getName() + " value = " + value);if ("special".equals(value)) {// 遇到特殊任务标记,就让当前线程等一下barrier.await();}}} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}, "thread01").start();new Thread(()->{try {List<String> list = matrix.get(1);for (String value : list) {TimeUnit.SECONDS.sleep(1);System.out.println(Thread.currentThread().getName() + " value = " + value);if ("special".equals(value)) {// 遇到特殊任务标记,就让当前线程等一下barrier.await();}}} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}, "thread02").start();new Thread(()->{try {List<String> list = matrix.get(2);for (String value : list) {TimeUnit.SECONDS.sleep(1);System.out.println(Thread.currentThread().getName() + " value = " + value);if ("special".equals(value)) {// 遇到特殊任务标记,就让当前线程等一下barrier.await();}}} catch (InterruptedException e) {e.printStackTrace();} catch (BrokenBarrierException e) {e.printStackTrace();}}, "thread03").start();}}

4.3 Semaphore

4.3.1 常规方式使用

使用 Semaphore 可以帮助我们管理资源位;当某个线程申请资源时,由 Semaphore 检查这个资源是否可用;如果其他线程释放了这个资源,那么申请资源的线程就可以使用。

// 1、创建 Semaphore 对象,指定资源数量为 3
Semaphore semaphore = new Semaphore(3);// 2、创建 10 个线程争夺这 3 个资源
for (int i = 0; i < 10; i++) {new Thread(() -> {try {// 申请资源semaphore.acquire();// 拿到资源执行操作System.out.println("【" + Thread.currentThread().getName() + "】号车辆【驶入】车位");TimeUnit.SECONDS.sleep(3);System.out.println("【" + Thread.currentThread().getName() + "】号车辆【驶出】车位");} catch (InterruptedException e) {e.printStackTrace();} finally {// 操作完成释放资源semaphore.release();}}, i + "").start();
}

4.3.2 引入超时机制

// 1、设定车位数量
int carPositionCount = 3;// 2、创建 Semaphore 对象
Semaphore semaphore = new Semaphore(carPositionCount);// 3、创建 50 个线程抢车位
for (int i = 0; i < 50; i++) {int carNum = i;new Thread(()->{boolean acquireResult = false;try {// 线程开始时先申请资源,申请不到会进入等待状态// 申请资源方式一:不见不散,等不到资源就一直等// semaphore.acquire();// 申请资源方式二:过时不候acquireResult = semaphore.tryAcquire(3, TimeUnit.SECONDS);if (acquireResult) {// 申请到资源时,线程会继续执行System.out.println(carNum + "号车辆驶入车位");// 车辆在车位停放一段时间TimeUnit.SECONDS.sleep(2);// 停放完成离开车位System.out.println(carNum + "号车辆驶出车位");} else {System.out.println(carNum + "号车辆放弃等待");}} catch (Exception e) {e.printStackTrace();} finally {// 判断当前线程释放拿到了资源if (acquireResult) {// 任务执行完成释放资源semaphore.release();}}}).start();}    

4.3.3 应用场景举例

借助Semaphore实现『限流』操作。

  • 当前服务器实例能够承受多大的访问量——设置为资源的数量。
  • 根据资源的数量创建Semaphore对象。
  • 服务器实例接收到请求通过Semaphore对象管理处理请求数量。
    • 在能力范围内:处理请求。
    • 超过能力范围:设定等待时间,看是否能够得到别的请求处理完成释放资源。

4.4 Fork Join

4.4.1 介绍

使用 Fork Join 框架能够帮助我们把一个大型任务,根据一定规律,拆分成小任务执行。如果拆分后的任务还不够小,可以以递归模式继续拆分,直到拆分到可以执行的程度。然后再把各个子任务执行的结果汇总到一起。

  • Fork:拆分:把大任务拆分成小任务。
  • Join:合并:把小任务执行的结果合并到一起。

在这里插入图片描述

4.4.2 API介绍

RescursiveTask

在这里插入图片描述

我们使用 Fork Join 框架只需要继承 RecursiveTask,然后重写 compute() 方法即可。在 compute() 方法中需要包含:

  • 任务拆分的逻辑
  • 任务拆分的操作:调用 fork() 方法
  • 已拆分任务的合并:调用 join() 方法
  • 子任务结果的合并:将 join() 方法的返回值合并起来
ForkJoinTask

ForkJoinTask 类是 RecursiveTask 的父类。

在这里插入图片描述

4.4.3 案例

需求

完成从 1~100 的累加。

代码
// 任务类
class MyTask extends RecursiveTask {// 区间开始位置private int begin;// 区间结束位置private int end;// 区间调整值:要通过拆分任务将区间调整到 10 以内public static final int ADJUST_VALUE = 10;// 保存当前任务的结果private int result = 0;// 声明构造器,设定当前任务的开始和结束位置public MyTask(int begin, int end) {this.begin = begin;this.end = end;}@Overrideprotected Object compute() {// 1、判断当前区间是否是原子任务中可以执行计算的范围if (end - begin <= ADJUST_VALUE) {for (int i = begin; i <= end ; i++) {result  = result + i;}} else {// 2、计算新拆分任务的区间范围int leftBegin = begin;int leftEnd = (begin + end) / 2;int rightBegin = leftEnd + 1;int rightEnd = end;// 3、创建两个新的任务(子任务)MyTask myTaskLeft = new MyTask(leftBegin, leftEnd);MyTask myTaskRight = new MyTask(rightBegin, rightEnd);// 4、调用框架提供的 fork() 进一步拆分任务myTaskLeft.fork();myTaskRight.fork();// 5、调用框架提供的 join() 获取子任务计算的结果int leftResult = (int) myTaskLeft.join();int rightResult = (int) myTaskRight.join();// 6、把子任务的结果合并到一起result = leftResult + rightResult;}return result;}}// 测试代码
// 1、创建 Fork Join 任务池
ForkJoinPool pool = new ForkJoinPool();// 2、创建任务对象
MyTask myTask = new MyTask(1, 100);// 3、将任务对象提交到任务池
ForkJoinTask forkJoinTask = pool.submit(myTask);// 4、获取任务执行结果
int finalResult = (int) forkJoinTask.get();System.out.println("finalResult = " + finalResult);

相关文章:

【Java多线程】4——特定场景解决办法

4 特定场景解决方法 ⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记仓库&#x1f449;https://github.com/A-BigTree/tree-learning-notes 个人主页&#x1f449;https://www.abigtree.top ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个st…...

Python:语法糖

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 在编程世界中&#xff0c;有一个词语听起来既甜蜜又神秘&#xff1a;语法糖&#xff08;Syntactic Sugar&#xff09;。这个术语并不是指真正的糖…...

nginx mirror 流量镜像

流量镜像 (Traffic Mirroring)&#xff0c;也称为流量影子 (Traffic Shadowing)&#xff0c;是一种强大的、无风险的测试应用版本的方法&#xff0c;它将实时流量的副本发送给被镜像的服务。 采用这种方法&#xff0c;您可以搭建一个与原环境类似的环境以进行验收测试&#xff…...

霉霉说地道中文,口型、卡点几乎完美,网友:配音时代结束了?

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了人工智能中文站 每天给大家更新可用的国内可用chatGPT资源 更多资源欢迎关注 「给电影配音的时代即将结束了。」 AI 的发展让很多人直呼饭碗被抢了&#xff0c;以前是艺术家、程序员…… 现在配音员也要失业了&a…...

【生活】相机/图像各参数

文章目录 专业模式图片编辑-滤镜实体滤镜软件模拟滤镜 图片编辑-增强曝光亮度对比度饱和度自然饱和度色温色调高光阴影HSL色调分离褪色颗粒锐化晕影清晰度暗角 参考 专业模式 第一个参数WB是白平衡&#xff0c;调节色彩的。 第二个是对焦F&#xff0c;近距离拍摄物体&#xf…...

白酒:浓香型白酒的典型代表与特点

云仓酒庄的豪迈白酒作为白酒的品牌&#xff0c;具有一系列与众不同的特点和优势。下面云仓酒庄的豪迈白酒将从典型性、品质、口感和包装等方面深入分析白酒的特点&#xff0c;以及它如何体现浓香型白酒的魅力。 浓香型白酒是中国白酒的重要分支&#xff0c;以浓郁的香味和与众不…...

百万组通用编码器 L1527芯片产品介绍,重码率很低

L1527 是 CMOS 结构的预烧内码&#xff08;遥控中的地址码&#xff09;通用编码器&#xff0c;内有 20 位可预烧写 100 万组内码组合&#xff0c;使得重码率很低&#xff0c;具有更高安全性。芯片内集成误操作禁止功能&#xff0c;在按键输入有效且状态不变时&#xff0c;芯片连…...

2024年有哪些证书值得考?推荐这四个

一句老话说得好&#xff0c;技多不压身&#xff0c;在工作中&#xff0c;也能够提升自身的竞争力。对于大多数人来说&#xff0c;考“证”也许是另一种提升自己的途径。那么在新的一年中&#xff0c;有哪些证书值得我们去拼一拼呢?一起来看看吧! 免费送备考资料。联系我们&am…...

下载最新VMware,专业版本

VMware - Delivering a Digital Foundation For BusinessesRun any app on any cloud on any device with a digital foundation built on VMware solutions for modern apps, multi-cloud, digital workspace, security & networking.https://www.vmware.com/ 官网地址...

卷积神经网络-卷积层

卷积神经网络-卷积层 1多层感知机&#xff08;MLP&#xff09;2卷积神经网络&#xff08;CNN&#xff09;3MLP和CNN关系与区别4仍然有人使用MLP的原因&#xff1a;5MLP的局限性&#xff1a;MLP的应用领域&#xff1a;总结&#xff1a;6全连接到卷积全连接层 vs 卷积层结构差异应…...

yolov8 pose keypoint解读

yolov8进行关键点检测的代码如下&#xff1a; from ultralytics import YOLO# Load a model model YOLO(yolov8n.pt) # pretrained YOLOv8n model# Run batched inference on a list of images results model([im1.jpg, im2.jpg]) # return a list of Results objects# Pr…...

kubernetes-Pod基于污点、容忍度、亲和性的多种调度策略(一)

Pod调度策略 一.标签1.什么是标签2.给Pod资源打标签3.给Node节点打标签4.查看标签资源 二.Node选择器1.nodeName(指定Pod调度到指定Node节点)2.nodeSelector(指定Pod调度到具有指定标签的Node节点) 三.亲和性1.Node亲和性-nodeAffinity2.Pod亲和性-pod-Affinity3.Pod反亲和性-p…...

Jenkins磁盘空间批量清理脚本

一、简介 Jenkins如果没有设置保留构建历史数&#xff0c;磁盘会随着使用次数增加而越来越满&#xff0c;于是需要批量清理一下。 二、清理脚本 找到Script Console 输入脚本&#xff0c;并点击执行&#xff0c;需要注意期望删除的构建历史编号&#xff08;可以查看下面的效果…...

FFmpeg拉取RTSP流并定时生成10秒短视频

生成效果: 视频时长为10秒 生成格式为FLV 输出日志: 完整实现代码如下: 需要在Mac和终端先安装FFmpeg brew install ffmpeg CMake文件配置: cmake_minimum_required(VERSION 3.27) project(ffmpeg_open_stream) set(CMAKE_CXX_STANDARD 17)#头文件包目录 include_director…...

【boost_search搜索引擎】2.正排索引和倒排索引

首先&#xff0c;要制作搜索引擎&#xff0c;我们首先要了解&#xff0c;什么是正排索引&#xff0c;什么是倒排索引&#xff0c;这是一个搜索引擎的关键。 1.正排索引 正排索引&#xff0c;其实就是我们的每一个文档&#xff0c;对应一个文档id。 正如vector容器一样&#xf…...

Java与Go:字符串转IP

在本文中&#xff0c;我们将了解如何将简单的对比Java和Go是如何将字符串解析为IP地址。 Java 在Java中&#xff0c;将字符串转换为IP地址最无脑的一个方法&#xff1a; import java.net.InetAddress; import java.net.UnknownHostException;public class Main {public stat…...

SlerfTools:简化操作,激发Solana生态创新潜能

在区块链世界的快速演变中,Solana生态系统以其独特的高性能吸引了全球的目光。然而,随着生态系统的蓬勃发展,用户和开发者面临的挑战也日渐增多。正是在这样的背景下,一个名为SlerfTools的新星项目应运而生,它承诺将为Solana带来一场革命性的变革。 项目的诞生 SlerfTools并非…...

AI视频风格转换动漫风:Stable Diffusion+TemporalKit

话不多说&#xff0c;直接开干。 基本方法 首先通过 Temporal-Kit 这个插件提取视频中的关键帧图片&#xff0c;然后使用 Stable Diffusion WebUI 重绘关键帧图片&#xff0c;然后再使用 Temporal-Kit 处理转换后的关键帧图片&#xff0c;它会自动补充关键帧之间的图片&#…...

MongoDB 7.x 绑定多个IP(bindIp)和IP范围段(IP/24)

早上安装了最新版的MOngoDB7.0&#xff0c;仅仅是想测试一些功能&#xff0c;暂无复杂操作的想法。 于是在远程的机器上&#xff0c;安装启动&#xff0c;一切正常。 网上找了教程&#xff0c;绑定IP的做法基本是修改mongod.cfg文件中的bindIp属性&#xff1a; Windows系统的…...

ERP系统帮助芯片公司成本如何计算 ?

在高度信息化的今天&#xff0c;企业运营管理逐渐趋向数字化、精准化&#xff0c;ERP系统作为集成一体化的企业管理软件&#xff0c;正在越来越多地被应用于企业的成本管理中。对于芯片公司而言&#xff0c;ERP系统不仅能够帮助其实现物料、人力、财务等资源的全面管理&#xf…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版&#xff0c;莫兰迪调色板清新简约工作汇报PPT模版&#xff0c;莫兰迪时尚风极简设计PPT模版&#xff0c;大学生毕业论文答辩PPT模版&#xff0c;莫兰迪配色总结计划简约商务通用PPT模版&#xff0c;莫兰迪商务汇报PPT模版&#xff0c;…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...