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() 时,进入等待状态,直到等待线程数等于栅栏数; 所有线程到达后,执行屏障动作(如果有),然后重置计数器,开启下一轮。 典型场景 多线程分阶段任务:比如“数据加载→数据计算→数据汇总”,每个阶段所有线程完成后进入下阶段; 模拟并发:让多个线程同时开始执行。
阅读全文