常用的同步辅助类

CountDownLatch

CountDownLatch 的基本使用

CountDownLatch 通过一个计数器来跟踪某些操作的完成次数 。线程会被阻塞直到计数器变为零 。一般来说,CountDownLatch 用于以下场景:

  • 等待多个线程执行完成:例如,等待多个子线程完成任务后,主线程再继续执行。
  • 并行任务的同步:确保一些任务在所有子任务完成之后才继续执行。
csharp 复制代码
public class CountDownLatchTest {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(5);
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "执行完毕");
                countDownLatch.countDown();
            }, "t" + i).start();
        }
        System.out.println("等待所有线程执行完毕");
    }
}

CountDownLatch ****的关键方法

await() 使当前线程等待 ,直到计数器的值为零。该方法是阻塞的,线程会在此方法处被挂起,直到计数器的值减为 0。

CountDownLatch 的应用场景

  1. 等待多个线程完成任务
    • 比如,在一个任务分解为多个子任务的场景中,我们希望等所有的子任务完成后,再继续进行下一个步骤。CountDownLatch 就可以用来保证主线程等到所有子线程的任务完成后再继续执行。
  1. 并行任务的同步控制
    • 比如,某些操作必须等到多个任务执行完成后才能继续,CountDownLatch 可以确保这些任务完成后才继续处理。
  1. 启动多个线程并等待其完成
    • 比如,在并行处理的情况下,启动多个线程并在主线程中等待所有线程的完成,可以通过 CountDownLatch 来实现。

总之就是在某些场景下,必须等待一些线程完成后才能继续进行就可以使用这个 CountDownLatch****


CyclicBarrier

CyclicBarrier 的基本原理

CyclicBarrier 使得多个线程在执行某个任务时,必须等待其他线程到达屏障点。每当所有线程都到达屏障点时,CyclicBarrier 会让这些线程继续执行。可以理解为它提供了一种线程间的协作方式,多个线程在到达同步点时会被阻塞,直到所有线程都到达这个点。

CountDownLatch 不同,CyclicBarrier可重用 的。CountDownLatch 一旦计数器变为零后就不能重用,而 CyclicBarrier 在每次屏障点通过后,可以重置为初始状态,允许进行下一轮的等待。

CyclicBarrier 的关键方法

await() :每个线程调用此方法,表示该线程已经到达了屏障点并且等待其他线程的到达。调用 await() 方法的线程会被阻塞,直到所有线程都到达屏障点。

csharp 复制代码
public class CyclicBarrierTest {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("集齐7颗龙珠,召唤神龙");
        });
        // 创建7个线程模拟收集龙珠
        for (int i = 1; i <= 7; i++) {
            final int tempInt = i;
            new Thread(() -> {
                try {
                    System.out.println("收集到第" + tempInt + "颗龙珠");
                    // 每个线程到达屏障时调用await
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

CyclicBarrier 的应用场景

  • 并行任务的同步 :比如你有多个线程并行执行任务,每个线程执行完任务后都需要等待其他线程完成某些操作再继续,CyclicBarrier 可以用来在这些线程之间同步操作。
  • 分批执行的任务:多个任务被分成多个子任务并行处理,每次等待所有子任务完成后再进行下一轮操作。
  • 分阶段执行 :比如某个计算任务分为多个阶段,每个阶段都需要多个线程协作,CyclicBarrier 可以确保每个阶段的任务都在所有线程完成后同步进行

在这种情况下会发生死锁

总结

  • CyclicBarrier 是一个同步工具类,允许多个线程在执行任务时相互等待,直到所有线程都到达屏障点后才继续执行。
  • 它是 可重用 的,并且适用于需要线程间在多个阶段同步执行的场景。
  • 使用 CyclicBarrier 时需要注意可能的死锁问题,以及适当处理线程中断和屏障破坏的异常。

Semaphore

Semaphore 的基本原理

Semaphore 维护了一个许可证计数器。每当一个线程请求资源时,它尝试从 Semaphore 中获取一个许可证,如果计数器大于 0,则获取一个许可证并将计数器减 1;否则线程会被阻塞,直到有许可证可用。释放资源时,线程释放许可证,计数器加 1,其他等待的线程可以继续执行。

Semaphore 的关键方法

acquire() :请求一个许可证。如果没有可用的许可证,当前线程会阻塞直到有许可证可用。

release() :释放一个许可证,使得其他等待的线程能够获得许可。如果有线程在等待许可证,release() 会唤醒其中一个线程。

Semaphore 应用场景

  • 限制并发线程数:通过限制某个资源的并发访问数量。例如,限制数据库连接池中最大连接数,或者限制网络带宽的并发访问。
  • 访问控制:控制对某些资源(如文件、设备等)的并发访问,确保同时访问资源的线程数不会超过设定的阈值。
  • 限流控制 :在 Web 服务或 API 中,使用 Semaphore 可以实现对请求的并发数限制,从而防止服务器被过多请求压垮。

总结

一个加法计数器 一个减法计数器 一个信号量

特性 Semaphore CountDownLatch CyclicBarrier
主要功能 控制并发线程数,管理资源池 等待多个线程执行完毕,或者多个线程完成后继续执行 等待多个线程到达屏障点后继续执行
可重用性 可重用:允许多次获取和释放许可证 不可重用:计数器归零后不能重置 可重用:每次所有线程到达屏障后,可以重用
适用场景 控制并发访问共享资源 等待多个线程完成后统一执行某些操作 多阶段任务的同步,多个线程在不同阶段同步
阻塞与唤醒 线程通过 acquire() 获取许可,release() 释放许可 线程通过 await() 等待,countDown() 减少计数器 线程通过 await() 等待,所有线程到达后继续执行
常见用途 资源池管理,流量控制,限流 并行任务同步,启动多个线程后等待它们完成 分阶段同步,线程池等同步任务
相关推荐
A-程序设计8 分钟前
基于Spring Boot+Vue的生活用品购物平台设计与实现-(源码+LW+可部署)
vue.js·spring boot·后端
k***z1110 分钟前
Spring boot创建时常用的依赖
java·spring boot·后端
计算机毕设定制辅导-无忧学长30 分钟前
基于Spring Boot的驾校管理系统
java·spring boot·后端
IT_陈寒1 小时前
SpringBoot3.0实战:5个高并发场景下的性能优化技巧,让你的应用快如闪电⚡
前端·人工智能·后端
p***23361 小时前
SpringBoot教程(三十二) SpringBoot集成Skywalking链路跟踪
spring boot·后端·skywalking
绝无仅有2 小时前
Elasticsearch经典面试题案例分析
后端·面试·架构
绝无仅有2 小时前
面试实战:如何实现一个完整的项目从注册到登录的功能?
后端·面试·架构
z***67772 小时前
Spring Data 什么是Spring Data 理解
java·后端·spring
f***a3462 小时前
SpringBoot 如何调用 WebService 接口
java·spring boot·后端