Java常用并发工具类原理与实战如何深入理解?
摘要:Java 并发工具类(JUC)提供了开箱即用的并发控制能力,避免我们重复造轮子。你提到的 CountDownLatch、CyclicBarrier、Semaphore、Exchanger 是最核心的四个,下面我会从核心作用、底层原理、使用场
Java 并发工具类(JUC)提供了开箱即用的并发控制能力,避免我们重复造轮子。你提到的 CountDownLatch、CyclicBarrier、Semaphore、Exchanger 是最核心的四个,下面我会从核心作用、底层原理、使用场景、代码示例四个维度,把每个工具类讲清楚,方便你理解和使用。
一、CountDownLatch:倒计时门闩(一次性)
核心作用
让一个或多个线程等待其他线程完成一组操作后,再继续执行(比如主线程等待所有子线程初始化完成)。
核心特性:一次性,计数器减到 0 后,无法重置,只能新建对象。
底层原理
基于 AQS(AbstractQueuedSynchronizer)实现:
CountDownLatch 内部维护一个计数器,初始化时设置为指定值;
调用 countDown() 时,计数器减 1(AQS 释放共享锁);
调用 await() 时,线程阻塞,直到计数器变为 0(AQS 获取共享锁成功)。
典型场景
主线程等待多个子线程完成初始化/任务执行;
并发测试:等待所有测试线程启动后,再统一开始计时。
代码示例
import java.util.concurrent.CountDownLatch;
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
int threadNum = 3;
// 初始化计数器为3
CountDownLatch latch = new CountDownLatch(threadNum);
for (int i = 1; i <= threadNum; i++) {
int taskId = i;
new Thread(() -> {
try {
System.out.println("任务" + taskId + "开始执行");
Thread.sleep(1000); // 模拟任务执行
System.out.println("任务" + taskId + "执行完成");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 计数器减1
latch.countDown();
}
}).start();
}
// 主线程等待所有子线程完成
latch.await();
System.out.println("所有任务执行完毕,主线程继续执行");
}
}
执行结果:
任务1开始执行
任务2开始执行
任务3开始执行
任务1执行完成
任务2执行完成
任务3执行完成
所有任务执行完毕,主线程继续执行
二、CyclicBarrier:循环栅栏(可重复)
核心作用
让一组线程互相等待,直到所有线程都到达某个“栅栏点”,然后所有线程同时继续执行(比如多线程计算后,统一汇总结果)。
核心特性:可循环使用,计数器重置后可再次使用;支持设置「屏障动作」,所有线程到达后执行。
底层原理
基于 ReentrantLock + Condition 实现(而非直接用 AQS):
内部维护「等待线程数」和「栅栏数」(每次到达栅栏点的线程数);
线程调用 await() 时,进入等待状态,直到等待线程数等于栅栏数;
所有线程到达后,执行屏障动作(如果有),然后重置计数器,开启下一轮。
典型场景
多线程分阶段任务:比如“数据加载→数据计算→数据汇总”,每个阶段所有线程完成后进入下阶段;
模拟并发:让多个线程同时开始执行。
