JUC工具类_CyclicBarrier与CountDownLatch

最近被问到CyclicBarrier和CountDownLatch相关的面试题,CountDownLatch平时工作中经常用到,但是CyclicBarrier没有用过,一时答不上来,因此简单总结记录一下

1.什么是CyclicBarrier?

1.1 概念

CyclicBarrier(循环屏障)是Java中的一个同步辅助类,它允许一组线程相互等待,直到达到某个公共屏障点。它的工作方式是,在所有参与线程都到达屏障之前,它们会一直等待。一旦最后一个线程到达屏障,所有被屏障等待的线程将被释放,可以继续执行后续的任务。

1.2 原理

CyclicBarrier内部维护了一个计数器,用于追踪到达屏障点的线程数量。当线程调用了CyclicBarrier的await()方法时,它会被阻塞,直到达到指定的等待数量。当最后一个线程调用await()方法时,屏障将打开,所有被阻塞的线程都会被释放,并且屏障会被重置以便下一次使用。

下面来看一下CyclicBarrier 主要属性

// ReentrantLock 重入锁
private final ReentrantLock lock = new ReentrantLock();
// 条件锁,等达到一定数量了再唤醒
private final Condition trip = lock.newCondition();
// 需要等待的线程数量
private final int parties;
// 当唤醒的时候执行的命令
private final Runnable barrierCommand;
// 代
private Generation generation = new Generation();
// 当前这一代还需要等待的线程数
private int count;

CyclicBarrier 存在如下构造方法,parties表示需要等待的线程数
在这里插入图片描述

CyclicBarrier 中await()方法表示等待线程,await()方法的实现逻辑来自dowait()方法
image-20231118010254634

好比如CyclicBarrier内部维护了一个计数器

image-20231118010352841

1.3 使用案例

CyclicBarrier可以用于解决需要多个线程协同工作的场景,例如将一个任务分成多个子任务并行执行,然后等待所有子任务完成后再继续执行后续操作。它也可以用于模拟多个线程相互等待的场景,直到所有线程都准备就绪,然后一起开始执行。

/**
 * <p>Class: TaskParallelExecution</p>
 * <p>Description: 使用CyclicBarrier演示多任务同时执行</p>
 *
 * @author zhouyi
 * @version 1.0
 * @date 2023/11/18
 */
public class TaskParallelExecution {
    private static final int NUM_THREADS = 4;

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(NUM_THREADS, () -> {
            System.out.println("All tasks completed. Proceeding to next step.");
        });

        for (int i = 0; i < NUM_THREADS; i++) {
            int threadNum = i;
            Thread t = new Thread(() -> {
                System.out.println("Task " + threadNum + " started.");
                // 模拟任务的执行
                try {
                    Thread.sleep(2000); // 假设任务需要2秒完成
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + threadNum + " completed.");
                try {
                    barrier.await(); // 等待其他线程完成任务
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + threadNum + " continues with the next step.");
            });
            t.start();
        }
    }
}

image-20231118011338132

在实际开发中,常见的还有如下几个业务场景,比如:

  • 数据处理并行化:在大规模数据处理中,可以将数据分成多个部分,每个部分由一个线程处理。使用CyclicBarrier,每个线程在处理完自己的数据后等待其他线程完成,然后进行下一步的数据合并或汇总操作。
  • 并行计算任务:在并行计算中,可以将一个大任务分解成多个子任务,并行处理。每个子任务处理一部分数据,然后等待其他子任务完成,最后合并结果。CyclicBarrier可用于同步各个子任务的执行。
  • 多线程任务协同:在某些场景下,多个线程需要协同工作,例如多个线程同时从不同的地方获取数据,然后合并处理这些数据。CyclicBarrier可用于等待所有线程都准备就绪后,再同时开始数据获取和处理的过程。

这些是一些使用CyclicBarrier的实际生产中的常见案例。CyclicBarrier提供了一种方便的同步机制,使多个线程能够协同工作,等待彼此达到一个共同的屏障点,然后再继续执行后续操作。

2.什么是CountDownLatch?

2.1 概念

CountDownLatch是Java中的一个同步辅助类,它允许一个或多个线程等待其他线程完成操作后再继续执行。它的工作方式与CyclicBarrier相反:它通过一个计数器来实现等待,计数器初始化为一个正整数,每个线程完成操作后会将计数器减1,直到计数器变为0,等待的线程才会被释放。

2.2 原理

CountDownLatch包含两个主要方法:

  • countDown():每当一个线程完成了所需的操作,调用该方法将计数器减1。
  • await():调用该方法的线程会阻塞,直到计数器变为0,即所有线程都完成了操作。

CountDownLatch通常用于一个线程等待其他若干个线程完成某个操作后再继续执行。例如,主线程希望等待多个子线程完成初始化操作后再开始执行某个任务,可以使用CountDownLatch来实现。

2.3 使用案例

使用CountDownLatch实现倒计时功能,例如模拟三个线程,当三个线程都一起执行结束后再统一交给主线程处理。

public class CountDownLatchExample {
    private static final int NUM_THREADS = 3;

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(NUM_THREADS);

        for (int i = 0; i < NUM_THREADS; i++) {
            Thread t = new Thread(() -> {
                // 模拟每个线程的操作
                System.out.println("Thread " + Thread.currentThread().getId() + " started.");
                try {
                    Thread.sleep(2000); // 假设每个线程需要2秒完成操作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread " + Thread.currentThread().getId() + " completed.");
                latch.countDown(); // 操作完成后将计数器减1
            });
            t.start();
        }

        System.out.println("Main thread is waiting for other threads to complete.");
        latch.await(); // 主线程等待计数器变为0
        System.out.println("All threads have completed. Proceeding with the main thread.");
    }
}

以上案例执行结果如下

image-20231118012905177

除了以上案例外,实际开发中经常遇到类似的场景,例如采用多线程处理大数据量导入,我们可以通过多线程分批读取数据、校验、封装数据,当以上几个环节都成功后(CountDownLatch 减少为0时)就可以进行写库操作,可以认为没有数据缺失。

3.总结

CyclicBarrier和CountDownLatch是Java中的两个同步辅助类,它们有一些共同点,但也存在一些区别。

共同点:

  1. 两者都是用于线程间的同步和协作,可以控制线程的执行顺序和并发性。
  2. 都使用一个计数器来控制等待和释放线程的操作。
  3. 都可以用于解决多线程之间的协同工作问题。

区别:

  1. 计数器行为不同:
    • CyclicBarrier的计数器可以重用,当计数器减到0时,所有等待的线程会被释放,计数器会被重置为初始值,可以继续使用。
    • CountDownLatch的计数器只能减少一次,一旦减到0,所有等待的线程会被释放,计数器不能重置或再次使用。
  2. 等待操作方式不同:
    • CyclicBarrier使用await()方法进行等待,当线程调用await()时,它会阻塞直到所有线程都到达屏障点,然后一起继续执行。
    • CountDownLatch使用await()方法进行等待,当线程调用await()时,它会阻塞直到计数器变为0,然后线程被释放。
  3. 使用场景不同:
    • CyclicBarrier通常用于将一个大任务分解为多个子任务并行执行,然后等待所有子任务完成后再继续执行后续操作。它适用于多线程协同工作的场景。
    • CountDownLatch通常用于一个或多个线程等待其他线程完成操作后再继续执行。它适用于线程之间的等待和同步的场景。

数器变为0,然后线程被释放。
3. 使用场景不同:

  • CyclicBarrier通常用于将一个大任务分解为多个子任务并行执行,然后等待所有子任务完成后再继续执行后续操作。它适用于多线程协同工作的场景。
  • CountDownLatch通常用于一个或多个线程等待其他线程完成操作后再继续执行。它适用于线程之间的等待和同步的场景。

CyclicBarrier和CountDownLatch都是用于线程间的同步和协作,但它们的计数器行为、等待操作方式和使用场景有所不同。CyclicBarrier适用于任务分解和并行执行的场景,而CountDownLatch适用于线程之间的等待和同步的场景。在选择使用时,需要根据具体需求来确定使用哪个类更合适。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MyBatis #{} 和 ${} 的区别

前言&#xff1a; #{} 和 ${} 的区别是 MyBatis 中一个常见的面试题&#xff0c;#{} 和 ${} 是MyBatis 中获取参数的两种方式&#xff0c;但我们在项目中大多数使用的都是 #{} 来获取参数&#xff0c;那么它们两个有什么区别呢&#xff1f; 区别 一. #{} 采用预编译 SQL&…

智能位移监测,更新传统井盖的功能

在城市的街道和人行道上&#xff0c;我们经常可以看到井盖的存在。井盖作为地下管道和设施的入口承载着重要的功能。然而过去我们可能忽视了一个重要的问题&#xff1a;井盖的位移可能会对人们产生潜在的威胁。为了保护我们的生活安全和交通畅通无阻和确保城市生命线安全稳定&a…

SQL Server如何建表

一、数据表的组成 实现完整性的约束有&#xff1a; –6个约束 –非空 not null –主键 primary key –唯一 unique –检查 check –默认 default –主键自增 identity 表约束 主键约束&#xff1a;值不能为null,且不能重复 非空约束&#xff1a;不能为null 默认约束&#xf…

004 OpenCV akaze特征点检测匹配

目录 一、环境 二、akaze特征点算法 2.1、基本原理 2.2、实现过程 2.3、实际应用 2.4、优点与不足 三、代码 3.1、数据准备 3.2、完整代码 一、环境 本文使用环境为&#xff1a; Windows10Python 3.9.17opencv-python 4.8.0.74 二、akaze特征点算法 特征点检测算法…

Es 拼音搜索无法高亮

目录 背景&#xff1a; Es 版本&#xff1a; 第一步 第二步 &#xff08;错误步骤 - 只是记录过程&#xff09; 第三步 第四步 第五步 第六步 第七步 背景&#xff1a; app 原有的搜索功能无法进行拼音搜索&#xff0c;产品希望可以支持&#xff0c;例如内容中含有&a…

rv1126-rv1109-openssh

这是一个工具&#xff0c;可以通过ssh远程登录来操作&#xff0c;非常逆天&#xff01; 于是rv1109代码自身自带有openssh 所以只需要打开config即可 diff --git a/buildroot/configs/rockchip_rv1126_rv1109_spi_nand_defconfig b/buildroot/configs/rockchip_rv1126_rv1109…

【力扣】从零开始的动态规划

【力扣】从零开始的动态规划 文章目录 【力扣】从零开始的动态规划开头139. 单词拆分解题思路 45. 跳跃游戏 II解题思路 5. 最长回文子串解题思路 1143. 最长公共子序列解题思路 931. 下降路径最小和解题思路 开头 本力扣题解用5题来引出动态规划的解题步骤&#xff0c;用于本…

我的 2023 秋招总结,拿到了大厂offer

2023秋招小结 前言 & 介绍 作为2024年毕业的学生&#xff0c;在2023年也就是今年秋招。 现在秋招快结束了&#xff0c;人生可能没有几次秋招的机会&#xff08;应该就一次&#xff0c;最多两次吧哈哈&#xff09;&#xff0c;也有一点感悟&#xff0c;所以小小总结一下。…

Unity中Shader纹理的过滤

文章目录 前言一、为什么要过滤&#xff1f;二、过滤方式1、Point(no filter) 无过滤2、Bilinear 双线性过滤3、Trilinear 三线性过滤 前言 Unity中Shader纹理的过滤 一、为什么要过滤&#xff1f; 事实上没有一个纹理上的纹素是与屏幕上的像素是一一对应的。 屏幕上的 一个…

【大模型应用开发教程】动手学大模型应用开发,一起探索LLM Universe

动手学大模型应用开发 01 开源初心02 教程内容03 学习指南04 文章最后 原文链接-奇想星球 LLM 正逐步成为信息世界的新革命力量&#xff0c;其通过强大的自然语言理解、自然语言生成能力&#xff0c;为开发者提供了新的、更强大的应用开发选择。随着国内外井喷式的 LLM API 服…

Flutter笔记:桌面应用 窗口定制库 bitsdojo_window

Flutter笔记 桌面应用窗口管理库 bitsdojo_window 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/13446…

开源与闭源:大模型时代的技术交融与商业平衡

一、开源和闭源的优劣势比较 1.1 开源 优势&#xff1a; 1.技术共享与吸引人才&#xff1a; 开源促进了技术共享&#xff0c;吸引了全球范围内的人才参与大模型的发展&#xff0c;形成了庞大的开发者社区。 2.推动创新&#xff1a; 开源模式鼓励开发者共同参与&#xff0c;推动…

LrC ACR :优化的 AI 天空蒙版

在 Lightroom Classic 和 Adobe Camera Raw 中创建基于 AI 技术的天空蒙版时&#xff0c;可能由于底层算法的原因&#xff0c;选中的天空蒙版在边缘处有晕开的现象&#xff08;又称为“出血” Bleed&#xff09;&#xff0c;从而导致天空蒙版不是很精准。 本文提供了一种特殊方…

vue监听对象属性值变化

一、官方文档 二、实现方法 方法一、直接根据watch来监听 export default {data() {return {object: {username: ,password: }}},watch: {object.username(newVal, oldVal) {console.log(newVal, oldVal)}} }方法二&#xff1a;利用watch和computed来实现监听 利用computed定…

腾讯云4核8G服务器配置价格表,轻量和CVM标准型S5实例

腾讯云4核8G服务器S5和轻量应用服务器优惠价格表&#xff0c;轻量应用服务器和CVM云服务器均有活动&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;轻量应用服务器4核8G12M带宽一年446元、529元15个月&#xff0c;腾讯云…

【LeetCode刷题日志】20.有效的括号

&#x1f388;个人主页&#xff1a;库库的里昂 &#x1f390;C/C领域新星创作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏✨收录专栏&#xff1a;LeetCode 刷题日志&#x1f91d;希望作者的文章能对你有所帮助&#xff0c;有不足的地方请在评论区留言指正&#xff0c;…

php中RESTful API使用

1、RESTful AP是什么 RESTful API是一种软件架构风格 RESTful API基于HTTP协议&#xff0c;并遵循一系列约定和原则。它的设计理念是将资源&#xff08;Resource&#xff09;作为核心概念&#xff0c;并通过一组统一的接口对资源进行操作。API的资源通常通过URL进行标识&…

3DMAX平铺插件MaxTiles教程

MaxTiles 结合了一组材质和地图插件&#xff0c;任何建筑师或 3D 可视化艺术家都会喜欢。与静态位图纹理不同&#xff0c;MaxTiles 材质可以更改键合图案、替换和混合砖块、更改边缘、随机化颜色、位置、表面等等。MaxTiles 结合了以下功能&#xff1a; 墙壁和瓷砖 – 用于创建…

腾讯云4核8G服务器性能如何多少钱一年?

腾讯云服务器4核8G配置优惠价格表&#xff0c;轻量应用服务器和CVM云服务器均有活动&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;轻量应用服务器4核8G12M带宽一年446元、529元15个月&#xff0c;腾讯云百科txybk.com分…

使用 Redis BitMap 实现签到与查询历史签到以及签到统计功能(SpringBoot环境)

目录 一、前言二、Redis BitMap 位图原理2.1、BitMap 能解决什么2.2、BitMap 存储空间计算2.3、BitMap 存在问题 三、Redis BitMap 操作基本语法和原生实现签到3.1、基本语法3.2、Redis BitMap 实现签到操作指令 四、SpringBoot 使用 Redis BitMap 实现签到与统计功能4.1、代码…