[并发控制]CountDownLatch和CyclicBarrier

简介: [并发控制]CountDownLatch和CyclicBarrier

等待唤醒机制

在java.util.concurrent包下 有许多并发工具来帮我们以简单的方式实现多线程的各种机制

今天我们来看CountDownLatch和CyclicBarrier,他们都能实现使线程间等待和唤醒机制。

CountDownLanch

先来看CountDownLatch,它最主要的方法是countDown(),和await()方法。CountDownLatch允许定义一个数量 表示要等待的线程数。假如有这么一个情景,某个线程需要等待执行某些任务的5个线程执行完毕后在执行。此时可以使用CountDownLatch的构造器传入需要等待的线程数。

 final CountDownLatch latch = new CountDownLatch(5);

然后启动五个线程

 for (int i = 0; i < 5; i++) {
    Thread th = new Thread(new Task(latch ));
    th.start();
 }

在每个线程执行完任务后调用latch.countDown()

需要等待的线程需要调用lanch.await(),然后将需要等待的线程和五个线程同时启动你会看到,5个线程是先执行的

实例:

package thread;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
 * 假设有三个同学 老师必须等到三个同学都完成作业才开始检查
 */
public class CountDownLanchTest {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        final CountDownLatch latch = new CountDownLatch(3);
        Student s1 = new Student(latch);
        Student s2 = new Student(latch);
        Student s3 = new Student(latch);
        Thread teacher = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    latch.await();
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
                System.out.println("老师检查");
            }
        });
        executorService.execute(teacher);
        executorService.execute(s1);
        executorService.execute(s2);
        executorService.execute(s3);
        executorService.shutdown();
    }
}
class Student implements Runnable {
    private CountDownLatch latch;
    public Student(CountDownLatch latch) {
        this.latch = latch;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+ " begin do home work");
        try {
            //模拟做作业时间
            TimeUnit.MILLISECONDS.sleep(3000);
        } catch (InterruptedException interruptedException) {
            interruptedException.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "已完成");
        //完成作业 执行
        latch.countDown();
    }
}

执行结果:

pool-1-thread-2 begin do home work

pool-1-thread-4 begin do home work

pool-1-thread-3 begin do home work

pool-1-thread-2已完成

pool-1-thread-3已完成

pool-1-thread-4已完成

老师检查

CyclicBarrier

再说cyclicBarrier,其实他们俩有一点相似,CountDownLatch实现的是等待某一部分任务执行完毕,最后执行等待的任务。不同的是cyclicBarrier实现需要执行任务的一组线程相互等待,直至这些线程均已就绪才开始执行任务。发现了吗 前者是等待任务执行完毕,才执行等待任务,后者是等待执行任务的线程全部就绪,才一起开始执行任务。此外这个cyclicBarrier是可以重置的,本篇暂时不详细解释。并且cyclicBarrier的构造方法可以传入一个线程,此线程会在其它任务线程均已就绪后执行。

来看示例:

package thread;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
 * 线程间相互等待 cyclicBarrier可复用
 * 类似跑步比赛 各位选手全部就位后 裁判才会打响发令枪
 */
public class CycleBarrierTest {
    public static void main(String[] args) {
    //定义需要等待的线程数,以及所有线程就绪后执行的任务
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
            @Override
            public void run() {
                System.out.println("5个线程就位");
            }
        });
        for (int i = 0; i < 5; i++) {
            Thread th = new Thread(new Task(cyclicBarrier));
            th.start();
        }
    }
}
class Task implements Runnable{
    private CyclicBarrier cyclicBarrier;
    public Task(CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " 已就位");
        try {
            cyclicBarrier.await();
        } catch (InterruptedException interruptedException) {
            interruptedException.printStackTrace();
        } catch (BrokenBarrierException e) {
           //e.printStackTrace();
            System.out.println(cyclicBarrier.isBroken());
        }
        //任务
        System.out.println(Thread.currentThread().getName() + " is running");
    }
}

执行结果:

Thread-0 已就位

Thread-4 已就位

Thread-2 已就位

Thread-1 已就位

Thread-3 已就位

5个线程就位

Thread-2 is running

Thread-4 is running

Thread-0 is running

Thread-3 is running

Thread-1 is running

假如理解了上面两个简单的例子,对这个两个类的使用应该就有一些谱了,其实看那么多概念不如马上动手实践一下,能更好的理解

总结:

CountLanch和CycleBarrier都可以实现线程等待,CountLanch 一般用于一个线程等待其它线程执行完毕,CycleBarrier用于一组线程等待至某个状态后一起执行;CycleBarrier可以重复使用CountLanch不行

目录
相关文章
|
6月前
|
算法 数据安全/隐私保护 异构计算
基于LSB最低有效位的音频水印嵌入提取算法FPGA实现,包含testbench和MATLAB对比
本项目展示了一种基于FPGA的音频水印算法,采用LSB(最低有效位)技术实现版权保护与数据追踪功能。使用Vivado2019.2和Matlab2022a开发,完整代码含中文注释及操作视频。算法通过修改音频采样点的最低有效位嵌入水印,人耳难以察觉变化。然而,面对滤波或压缩等攻击时,水印提取可能受影响。该项目运行效果无水印干扰,适合实时应用场景,核心逻辑简单高效,时间复杂度低。
|
9月前
|
IDE 开发工具
【开发IDE升级】如何对IDEA版本进行升级
本文介绍了如何将 IntelliJ IDEA Ultimate 从 2020.2.2 版本升级到 2022.3.2 版本。主要内容包括准备工作、卸载旧版本和安装新版本的步骤。首先,从官网下载所需版本并备份旧版配置;接着,通过 Uninstall.exe 卸载旧版,保留配置和插件;最后,安装新版并完成激活。详细的操作步骤和截图帮助用户顺利完成升级过程。
10082 1
【开发IDE升级】如何对IDEA版本进行升级
|
前端开发 Java API
Java并发基础:CompletableFuture全面解析
CompletableFuture类使得并发任务的处理变得简单而高效,通过简洁的API,开发者能轻松创建、组合和链式调用异步操作,无需关心底层线程管理,这不仅提升了程序的响应速度,还优化了资源利用率,让复杂的并发逻辑变得易于掌控。
332 1
Java并发基础:CompletableFuture全面解析
|
10月前
|
缓存 容器 Perl
【Azure Container App】Container Apps 设置延迟删除 (terminationGracePeriodSeconds) 的解释
terminationGracePeriodSeconds : 这个参数的定义是从pod收到terminated signal到最终shutdown的最大时间,这段时间是给pod中的application 缓冲时间用来处理链接关闭,应用清理缓存的;并不是从idel 到 pod被shutdown之间的时间;且是最大时间,意味着如果application 已经gracefully shutdown,POD可能被提前terminated.
215 3
|
存储 NoSQL 数据挖掘
MongoDB 实时分析案例
【5月更文挑战第7天】
415 0
|
11月前
|
缓存 前端开发 JavaScript
ES6 全部特性详解
ES6 是 JavaScript 语言的一个重要升级,它引入了大量新的功能,极大地增强了 JavaScript 的表达力和可读性。通过了解和掌握这些特性,开发者可以编写出更加简洁、高效、优雅的代码,并轻松应对大型项目的复杂性。
247 7
|
安全 数据安全/隐私保护 UED
优化用户体验:前后端分离架构下Python WebSocket实时通信的性能考量
【7月更文挑战第17天】前后端分离趋势下,WebSocket成为实时通信的关键,Python有`websockets`等库支持WebSocket服务。与HTTP轮询相比,WebSocket减少延迟,提高响应。连接管理、消息传输效率、并发处理及安全性是性能考量重点。使用WebSocket能优化用户体验,尤其适合社交、游戏等实时场景。开发应考虑场景需求,充分利用WebSocket优势。
383 3
Invalid bound statement (not found)错误【已解决】
Invalid bound statement (not found)错误【已解决】
1792 1
|
前端开发 JavaScript Java
React 速通笔记
【7月更文挑战第17天】
147 1
|
Kubernetes 调度 Docker
Kubernetes(K8S) Pod 介绍
Kubernetes(K8S) Pod 介绍
284 0