常用的同步辅助类

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() 等待,所有线程到达后继续执行
常见用途 资源池管理,流量控制,限流 并行任务同步,启动多个线程后等待它们完成 分阶段同步,线程池等同步任务
相关推荐
程序员小假2 小时前
线程池执行过程中遇到异常该怎么办?
java·后端
Mr.Entropy2 小时前
Hibernate批量查询方法全面解析
java·后端·hibernate
绝顶少年3 小时前
Spring 框架中 RestTemplate 的使用方法
java·后端·spring
信安成长日记3 小时前
golang 写路由的时候要注意
开发语言·后端·golang
Lojarro3 小时前
GO学习2:基本数据类型 与 转换
后端·学习·golang
闲人编程3 小时前
2025年,如何选择Python Web框架:Django, Flask还是FastAPI?
前端·后端·python·django·flask·fastapi·web
karry_k3 小时前
Callable
后端
golang学习记3 小时前
从0死磕全栈之Next.js App Router 入门实战:5 分钟搭建一个待办事项(Todo List)应用
后端
PH = 74 小时前
Spring AI整合聊天模型DeepSeek
java·spring boot·后端