当前位置: 首页 > 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…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例&#xff1a;使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例&#xff1a;使用OpenAI GPT-3进…...

相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解

【关注我&#xff0c;后续持续新增专题博文&#xff0c;谢谢&#xff01;&#xff01;&#xff01;】 上一篇我们讲了&#xff1a; 这一篇我们开始讲&#xff1a; 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下&#xff1a; 一、场景操作步骤 操作步…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...