JUC框架(Semaphore、CountDownLatch、CyclicBarrier)

在这里插入图片描述

文章目录

    • Semaphore(信号量)
      • Semaphore介绍
      • Semaphore基本概念
      • Semaphore使用场景
      • Semaphore示例
    • CountDownLatch (计数器/闭锁)
      • CountDownLatch 介绍
      • CountDownLatch 基本概念
      • CountDownLatch 使用场景
      • CountDownLatch 基本方法
      • CountDownLatch 示例
    • CyclicBarrier(循环栅栏)
      • CyclicBarrier介绍
      • CyclicBarrier基本概念
      • CyclicBarrier使用场景
      • CyclicBarrier基本方法
      • CyclicBarrier示例(银行流水)
    • CyclicBarrier 和 CountDownLatch 的区别

更多相关内容可查看

Semaphore(信号量)

Semaphore介绍

Semaphore(信号量)是Java并发包java.util.concurrent中的一个类,它主要用于控制对多个共享资源的访问。与CountDownLatch和CyclicBarrier等并发工具不同,Semaphore通常用于限制对某个资源池(或称为资源集)的并发访问数量

Semaphore基本概念

  • 许可(Permits):Semaphore管理一组虚拟的许可,每个许可代表对一个资源的访问权限
  • 获取许可(Acquire):当一个线程需要访问一个资源时,它必须首先从Semaphore获取一个或多个许可。如果Semaphore中有足够的许可,则获取成功,线程可以继续执行;否则,线程将被阻塞,直到有可用的许可为止。
  • 释放许可(Release):当线程完成对资源的访问后,它应该释放先前获取的许可,以便其他线程可以访问该资源。

Semaphore使用场景

  • 资源池限制:例如,一个系统可能有10个数据库连接,而多个线程可能同时需要访问这些连接。使用Semaphore可以确保在任何时候,最多只有10个线程可以访问数据库连接。
  • 并发限制:有时,你可能希望限制同时执行特定操作的线程数量。例如,你可能希望同时只有5个线程可以访问某个API或执行某个计算密集型任务。

Semaphore示例

下面是一个简单的示例,展示了如何使用Semaphore来限制对资源池的并发访问:

import java.util.concurrent.Semaphore;  public class SemaphoreExample {  private final Semaphore semaphore;  private final int maxConcurrentAccess;  public SemaphoreExample(int maxConcurrentAccess) {  this.maxConcurrentAccess = maxConcurrentAccess;  this.semaphore = new Semaphore(maxConcurrentAccess);  }  public void accessResource() throws InterruptedException {  // 获取一个许可  semaphore.acquire();  try {  // 访问资源的代码...  System.out.println("Accessing resource. Remaining permits: " + semaphore.availablePermits());  // 模拟资源访问的耗时操作  Thread.sleep(1000);  } finally {  // 释放许可  semaphore.release();  }  }  public static void main(String[] args) {  SemaphoreExample example = new SemaphoreExample(3);  for (int i = 0; i < 5; i++) {  new Thread(() -> {  try {  example.accessResource();  } catch (InterruptedException e) {  e.printStackTrace();  }  }).start();  }  }  
}

可以看到, 在这个示例中,我们创建了一个Semaphore对象,其初始许可数量为3。然后,我们启动了5个线程来模拟对资源的并发访问。由于Semaphore的限制,在任何时候最多只有3个线程可以访问资源。

CountDownLatch (计数器/闭锁)

CountDownLatch 介绍

CountDownLatch 是 Java 并发工具包 java.util.concurrent 中的一个类,它允许一个或多个线程等待其他线程完成一组操作。CountDownLatch 的主要应用场景是协调多个线程,以便它们能够彼此等待,直到某个条件(一组操作的完成)被满足

CountDownLatch 基本概念

  • 计数器(Count):CountDownLatch 包含一个计数器,该计数器在创建 CountDownLatch
    对象时被初始化为给定的值。
  • 等待(Await):线程可以调用 await() 方法等待,该方法会阻塞线程,直到计数器达到零。
  • 计数(Count Down):当一个或多个线程完成了某个任务后,它们可以调用 countDown() 方法来减少计数器的值。

CountDownLatch 使用场景

  • 并行计算:你可以启动多个线程进行并行计算,并在所有线程都完成计算后,主线程继续执行后续操作。
  • 资源初始化:在应用程序启动时,可能需要加载或初始化一些资源。你可以使用多个线程并行加载资源,并在所有资源都加载完成后,主线程继续执行。

CountDownLatch 基本方法

  • CountDownLatch(int count):创建一个 CountDownLatch 实例,并设置计数器的初始值。
  • countDown():将计数器的值减一。如果计数器的值变为零,那么所有因调用 await() 方法而等待的线程将被唤醒。
  • await():使当前线程等待,直到计数器达到零。如果计数器已经是零,那么该方法立即返回。否则,线程将处于休眠状态,直到计数器变为零。
  • await(long timeout, TimeUnit unit):使当前线程等待,直到计数器达到零,或者等待时间超过了指定的超时时间。
  • getCount():返回计数器的当前值。

CountDownLatch 示例

  1. 某一线程在开始运行前等待 n 个线程执行完毕
    CountDownLatch 的计数器初始化为 n (new CountDownLatch(n)),每当一个任务线程执行完毕,就将计数器减 1 (countdownlatch.countDown()),当计数器的值变为 0 时,在 CountDownLatch 上 await() 的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。
@Test
void name() throws InterruptedException {//需求 : 有T1,T2,T3三个线程, 希望T1,T2,T3 按照顺序执行  join方法//需求 : T1,T2,T3执行完毕之后, 再执行主线程  CountDownLatch//线程计数器CountDownLatch latch = new CountDownLatch(3);Thread t1 = new Thread(() -> {try {Thread.sleep(10000);log.info("t1线程开始执行--------------");latch.countDown();} catch (InterruptedException e) {throw new RuntimeException(e);}});Thread t2 = new Thread(() -> {try {Thread.sleep(20000);log.info("t2线程开始执行--------------");latch.countDown();} catch (InterruptedException e) {throw new RuntimeException(e);}});Thread t3 = new Thread(() -> {try {Thread.sleep(30000);log.info("t3线程开始执行--------------");latch.countDown();} catch (InterruptedException e) {throw new RuntimeException(e);}});t1.start();t2.start();t3.start();latch.await();log.info("主线程执行-------");
}
  1. 实现多个线程开始执行任务的最大并行性
    注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的 CountDownLatch 对象,将其计数器初始化为 1 (new CountDownLatch(1)),多个线程在开始执行任务前首先 coundownlatch.await(),当主线程调用 countDown() 时,计数器变为 0,多个线程同时被唤醒
@Test
void name() throws InterruptedException {//需求 : 有T1,T2,T3三个线程, 希望T1,T2,T3 按照顺序执行  join方法//需求 : T1,T2,T3执行完毕之后, 再执行主线程  CountDownLatch//线程计数器CountDownLatch latch = new CountDownLatch(1);//RCountDownLatch latch = redissonClient.getCountDownLatch("countdown");//latch.trySetCount(3);Thread t1 = new Thread(() -> {try {latch.await();Thread.sleep(1000);log.info("t1线程开始执行--------------");} catch (InterruptedException e) {throw new RuntimeException(e);}});Thread t2 = new Thread(() -> {try {latch.await();Thread.sleep(2000);log.info("t2线程开始执行--------------");} catch (InterruptedException e) {throw new RuntimeException(e);}});Thread t3 = new Thread(() -> {try {latch.await();Thread.sleep(3000);log.info("t3线程开始执行--------------");} catch (InterruptedException e) {throw new RuntimeException(e);}});t1.start();t2.start();t3.start();log.info("主线程执行-------");latch.countDown();Thread.sleep(5000);
}

CyclicBarrier(循环栅栏)

CyclicBarrier介绍

CountDownLatch 是 Java 并发工具包 java.util.concurrent 中的一个类,它允许一个或多个线程等待其他线程完成一组操作。CountDownLatch 的主要应用场景是协调多个线程,以便它们能够彼此等待,直到某个条件(一组操作的完成)被满足。

CyclicBarrier基本概念

  • 计数器(Count):CountDownLatch 包含一个计数器,该计数器在创建 CountDownLatch
    对象时被初始化为给定的值。
  • 等待(Await):线程可以调用 await() 方法等待,该方法会阻塞线程,直到计数器达到零。
  • 计数(Count Down):当一个或多个线程完成了某个任务后,它们可以调用 countDown() 方法来减少计数器的值。

CyclicBarrier使用场景

  • 并行计算:你可以启动多个线程进行并行计算,并在所有线程都完成计算后,主线程继续执行后续操作。
  • 资源初始化:在应用程序启动时,可能需要加载或初始化一些资源。你可以使用多个线程并行加载资源,并在所有资源都加载完成后,主线程继续执行。

CyclicBarrier基本方法

  • CountDownLatch(int count):创建一个 CountDownLatch 实例,并设置计数器的初始值。
  • countDown():将计数器的值减一。如果计数器的值变为零,那么所有因调用 await() 方法而等待的线程将被唤醒。
  • await():使当前线程等待,直到计数器达到零。如果计数器已经是零,那么该方法立即返回。否则,线程将处于休眠状态,直到计数器变为零。
  • await(long timeout, TimeUnit unit):使当前线程等待,直到计数器达到零,或者等待时间超过了指定的超时时间。
  • getCount():返回计数器的当前值。

CyclicBarrier示例(银行流水)

CyclicBarrier 可以用于多线程计算数据,最后合并计算结果的应用场景。比如我们用一个 Excel 保存了用户所有银行流水,每个 Sheet 保存一个帐户近一年的每笔银行流水,现在需要统计用户的日均银行流水,先用多线程处理每个 sheet 里的银行流水,都执行完之后,得到每个 sheet 的日均银行流水,最后,再用 barrierAction 用这些线程的计算结果,计算出整个 Excel 的日均银行流水。可以看到当线程数量也就是请求数量达到我们定义的 5 个的时候, await() 方法之后的方法才被执行。
另外,CyclicBarrier 还提供一个更高级的构造函数 CyclicBarrier(int parties, Runnable barrierAction),用于在线程到达屏障时,优先执行 barrierAction,方便处理更复杂的业务场景。示例代码如下:

import java.util.ArrayList;  
import java.util.List;  
import java.util.concurrent.BrokenBarrierException;  
import java.util.concurrent.CyclicBarrier;  public class BankTransactionProcessor {  private static final int NUM_THREADS = 5; // 假设有5个线程用于处理不同的sheet  public static void main(String[] args) {  // 创建一个CyclicBarrier,当所有线程处理完各自的sheet后,执行barrierAction  CyclicBarrier cyclicBarrier = new CyclicBarrier(NUM_THREADS, () -> {  // 这里是barrierAction,当所有sheet都处理完成后,执行这个操作来合并结果  List<Double> dailyAverages = new ArrayList<>();  // 假设dailyAverages是从各个线程中收集的  // 在这里计算整个Excel的日均银行流水  double totalAverage = dailyAverages.stream().mapToDouble(Double::doubleValue).average().orElse(0);  System.out.println("Total daily average bank transaction: " + totalAverage);  });  // 模拟处理Excel sheet的线程  for (int i = 0; i < NUM_THREADS; i++) {  final int sheetIndex = i;  new Thread(() -> {  try {  // 处理单个sheet的逻辑,假设得到每个sheet的日均银行流水  double dailyAverage = processSheet(sheetIndex);  // 这里可以假设有一个方式将dailyAverage加入到dailyAverages列表中  // 但是在这个示例中,我们只是打印出来  System.out.println("Sheet " + sheetIndex + " daily average bank transaction: " + dailyAverage);  // 等待所有sheet处理完毕  cyclicBarrier.await();  } catch (InterruptedException | BrokenBarrierException e) {  e.printStackTrace();  }  }).start();  }  }  // 模拟处理单个sheet的逻辑  private static double processSheet(int sheetIndex) {  // 这里应该是读取sheet数据,计算日均银行流水的逻辑  // 为了示例简单,我们直接返回一个模拟值  return sheetIndex * 1000.0; // 假设每个sheet的日均银行流水是递增的  }  
}

CyclicBarrier 和 CountDownLatch 的区别

  • CountDownLatch 的实现是基于 AQS 的,而 CycliBarrier 是基于 ReentrantLock

  • CountDownLatch 是计数器,只能使用一次,而 CyclicBarrier 的计数器提供 reset 功能,可以多次使用。

  • 对于 CountDownLatch 来说,重点是“一个线程(多个线程)等待”,而其他的 N 个线程在完成“某件事情”之后,可以终止,也可以等待。而对于
    CyclicBarrier,重点是多个线程,在任意一个线程没有完成,所有的线程都必须等待。

  • CountDownLatch 是计数器,线程完成一个记录一个,只不过计数不是递增而是递减,而 CyclicBarrier 更像是一个阀门,需要所有线程都到达,阀门才能打开,然后继续执行。

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

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

相关文章

分布式微服务之springboot学习

跟着韩顺平老师学Java SpringBoot基本介绍官方文档springboot是什么?springboot快速入门需求/图解说明完成步骤快速入门小结 Spring SpringMVC SpringBoot的关系梳理关系如何理解 -约定优于配置 依赖管理和自动配置依赖管理什么是依赖管理修改自动仲裁/默认版本号 starter场景…

mac 安装java jjdk8 jdk11 jdk17 等

oracle官网 https://www.oracle.com/java/technologies/downloads/ 查看当前电脑是英特尔的x86 还是arm uname -m 选择指定版本&#xff0c;指定平台的安装包&#xff1a; JDK8 JDK11的&#xff0c;需要当前页面往下拉&#xff1a; 下载到的安装包&#xff0c;双击安装&#x…

ChatGLM3-6B部署

ZhipuAI/chatglm3-6b 模型文件地址 ChatGLM3 代码仓库 ChatGLM3 技术文档 硬件环境 最低要求&#xff1a; 为了能够流畅运行 Int4 版本的 ChatGLM3-6B&#xff0c;最低的配置要求&#xff1a; 内存&#xff1a;> 8GB 显存: > 5GB&#xff08;1060 6GB,2060 6G…

[力扣]——231.2的幂

题目描述&#xff1a; 给你一个整数 n&#xff0c;请你判断该整数是否是 2 的幂次方。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 如果存在一个整数 x 使得 n 2x &#xff0c;则认为 n 是 2 的幂次方。 bool isPowerOfTwo(int n){ if(n0)retur…

3D技术的应用领域

3D技术在现代科技和工业中有广泛的应用&#xff0c;其涵盖的领域非常广泛&#xff0c;从娱乐到医学&#xff0c;再到制造业和建筑&#xff0c;3D技术正在改变我们理解和互动的方式。以下是一些主要的应用领域。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&…

如何获取某个城市或区域的人口分布数据?

人口分布数据在多个领域都扮演着至关重要的角色。这些数据不仅反映了一个国家或地区的人口分布状况&#xff0c;而且为政策制定者、企业决策者和研究者提供了宝贵的信息。那么&#xff0c;我们如何获取这些重要的人口分布数据呢&#xff1f; 政府统计部门是最主要的来源。各国政…

通用代码生成器应用场景二,快速原型

通用代码生成器应用场景二&#xff0c;快速原型 对项目经理&#xff0c;产品经理和售前工程师而言&#xff0c;开发快速原型是一种常见的需求。使用通用代码生成器&#xff0c;您可以更好&#xff0c;更快的开发系统的快速原型。通用代码生成器对完成CRUD和登录系统阶段的快速…

2024 NahamConCTF re 部分wp

IPromise 附件拖入ida main里没东西&#xff0c;但是函数列表很明显。直接在线网站解 Taylors First Swift 附件拖入ida&#xff0c;会提示识别到结构&#xff0c;选择yes 比较简单&#xff0c;可以直接猜异或之后再base64 Whats in the Box? 新遇见的题型&#xff0c;是用mak…

四元数学习总结(2)

导语&#xff1a;相比矩阵&#xff0c;用四元数处理3D旋转的优势是毋庸置疑的&#xff0c;但由于概念复杂&#xff0c;难于理解&#xff0c;一直令我摸不着头脑。最近学习更是发现在机器人、无人机、SLAM等先进领域&#xff0c;四元数被当成实数、整数这样的基础&#xff0c;所…

抄单 高频下单系统的功能都有什么?

1、多开&#xff1a;同一台电脑同一个账户无限数量登录&#xff08;登录后可独立新开合约&#xff0c;挂单&#xff0c;买卖等&#xff09;&#xff0c;多开后可使用三种不同切换方式来回切换&#xff0c;第一种为ALTTab切换、第二种为点击搜索条切换、第三种为点击下方任务栏切…

RT-Thread更改msh串口波特率

修改rt-thread文件下components下dirvers下serial.h文件里 #define RT_SERIAL_CONFIG_DEFAULT 里的默认波特率即可

Vue进阶之Vue项目实战(三)

Vue项目实战 图表渲染安装echarts图表渲染器(图表组件)图表举例&#xff1a;创建 ChartsRenderer.vue创建 ChartsDataTransformer.ts 基于 zrender 开发可视化物料安装 zrender画一个矩形画一个柱状图 基于svg开发可视化物料svg小示例使用d3进行图表渲染安装d3基本使用地图绘制…

柏拉图表征假说:AI模型趋同于现实的统一表征

引言 近日&#xff0c;Ilya Sutskever在离开OpenAI后不久点赞了一篇由MIT团队发表的AI论文&#xff0c;这篇题为《The Platonic Representation Hypothesis》的论文引起了广泛关注。这篇论文探讨了AI模型在不同数据和模态上的训练是否趋向于收敛成一个共享的现实世界统计模型。…

怎么识别图片中的文字呢!??

要识别图片中的文字&#xff0c;一般使用OCR软件来实现这一需求&#xff0c;下面以金某识别网页版为例&#xff0c;说说操作步骤&#xff1a; 一、点击“点击添加需转换的图片或PDF”&#xff0c;如还没登录将弹出登录窗口&#xff0c;直接登录即可&#xff0c;如已登录&#x…

基于 Wireshark 分析 UDP 协议

一、UDP 协议 UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是一种无连接的传输层协议&#xff0c;常用于传输即时数据&#xff0c;如音频、视频和实时游戏数据等。 UDP 的特点如下&#xff1a; 1. 无连接性&#xff1a;UDP 不需要在发送数…

计算机毕业设计 | SSM汽车租赁系统(附源码)

1&#xff0c; 概述 1.1 课题背景 随着社会的快速发展&#xff0c;计算机的影响是全面且深入的。用户生活水平的不断提高&#xff0c;日常生活中用户对汽车租赁系统方面的要求也在不断提高&#xff0c;需要汽车租赁系统查询的人数更是不断增加&#xff0c;使得汽车租赁系统的…

6-3 求二叉树的深度

作者 DS课程组 单位 临沂大学 本题要求实现一个函数&#xff0c;可返回二叉树的深度。 函数接口定义&#xff1a; int Depth(BiTree T);T是二叉树树根指针&#xff0c;函数Depth返回二叉树的深度&#xff0c;若树为空&#xff0c;返回0。 裁判测试程序样例&#xff1a; #in…

电商API接口:供应商价格与主流电商平台价格做比价

品牌在进行采购工作时&#xff0c;将供应商提供的价格与主流电商平台上的公开价格进行比价是一种非常常见的做法&#xff0c;这样做的目的主要是为了保证自身供应商提供的价格具有竞争力和合理性&#xff0c;从而更好地优化采购工作。 以下是过程中的具体步骤及一些注意事项&a…

基于springboot实现周边游平台个人管理系统项目【项目源码+论文说明】

基于springboot实现周边游平台个人管理系统演示 摘要 在如今社会上&#xff0c;关于信息上面的处理&#xff0c;没有任何一个企业或者个人会忽视&#xff0c;如何让信息急速传递&#xff0c;并且归档储存查询&#xff0c;采用之前的纸张记录模式已经不符合当前使用要求了。所以…

2024年上半年信息系统项目管理师下午真题及答案(第一批)

试题一 某项目包含ABCDEFGH共8个活动&#xff0c;各活动的历时、活动逻辑关系如下表所示&#xff1a; 单击下面头像图片领取更多软考独家资料