2026/5/18 20:21:05
网站建设
项目流程
12个优秀的平面设计素材网站的排名,做网站做系统,深圳市国外网站建设,百度门户网站在高并发系统中#xff0c;多个线程之间的协作是不可避免的。Java 从 JDK 1.5 开始引入了 java.util.concurrent#xff08;JUC#xff09;包#xff0c;其中包含了一系列强大的线程协作工具类#xff0c;极大简化了并发编程的复杂性。
CountDownLatch#xff08;JDK 5多个线程之间的协作是不可避免的。Java 从 JDK 1.5 开始引入了java.util.concurrentJUC包其中包含了一系列强大的线程协作工具类极大简化了并发编程的复杂性。CountDownLatchJDK 5倒计时门闩使用场景CountDownLatch常用于“一个或多个线程等待其他线程完成任务后再继续执行”的场景例如主线程等待所有子线程初始化完毕再启动服务。并发测试中模拟 N 个请求同时发出后统计总耗时。资源加载完成后统一触发后续逻辑。核心 APIpublic CountDownLatch(int count); // 初始化计数器 public void await() throws InterruptedException; // 阻塞等待计数归零 public boolean await(long timeout, TimeUnit unit); // 带超时的等待 public void countDown(); // 计数减一使用示例public class CountDownLatchExample { public static void main(String[] args) throws InterruptedException { int threadCount 5; CountDownLatch latch new CountDownLatch(threadCount); for (int i 0; i threadCount; i) { new Thread(() - { try { System.out.println(Thread.currentThread().getName() 正在执行任务...); Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { latch.countDown(); // 任务完成计数减一 } }).start(); } latch.await(); // 主线程等待所有任务完成 System.out.println(所有任务已完成主线程继续执行); } }输出Thread-0 正在执行任务... Thread-1 正在执行任务... Thread-3 正在执行任务... Thread-2 正在执行任务... Thread-4 正在执行任务... 所有任务已完成主线程继续执行应用场景示例服务启动检查// 等待数据库、缓存、消息队列初始化完成 CountDownLatch startupLatch new CountDownLatch(3); initDB(startupLatch); initCache(startupLatch); initMQ(startupLatch); startupLatch.await(); startHttpServer();使用注意点不可重用一旦计数归零无法再次使用除非新建实例。需要重复使用的场景应考虑CyclicBarrier若某个线程未调用countDown()会导致主线程永久阻塞 导致死锁所以务必在 finally 块中调用。await()可被中断需处理InterruptedException。底层原理CountDownLatch基于AQSAbstractQueuedSynchronizer实现AQS 原理详见Java并发编程Lock原理详解内部状态state表示剩余计数值。await()对应 AQS 的acquireSharedInterruptibly(1)尝试获取共享锁若state ! 0则入队阻塞。countDown()调用releaseShared(1)将state减 1当state 0时唤醒所有等待线程。CyclicBarrierJDK 5循环屏障使用场景CyclicBarrier适用于“多个线程互相等待全部到达某一点后才能继续”的场景例如多线程分阶段计算每阶段结束后汇总结果。游戏开发中等待所有玩家准备就绪。并行算法中的同步点。核心 APIpublic CyclicBarrier(int parties); public CyclicBarrier(int parties, Runnable barrierAction); // 所有线程到达后执行的动作 public int await() throws InterruptedException, BrokenBarrierException; public int await(long timeout, TimeUnit unit) throws ...; public void reset(); // 重置屏障可能中断当前等待使用示例public class CyclicBarrierExample { public static void main(String[] args) { CyclicBarrier barrier new CyclicBarrier(3, () - { System.out.println(所有线程已到达屏障执行汇总操作); }); for (int i 0; i 3; i) { new Thread(() - { try { System.out.println(Thread.currentThread().getName() 第一阶段完成); barrier.await(); // 等待其他线程 System.out.println(Thread.currentThread().getName() 第二阶段开始); } catch (Exception e) { e.printStackTrace(); } }).start(); } } }输出Thread-1 第一阶段完成 Thread-2 第一阶段完成 Thread-0 第一阶段完成 所有线程已到达屏障执行汇总操作 Thread-0 第二阶段开始 Thread-1 第二阶段开始 Thread-2 第二阶段开始应用场景示例多轮并行计算CyclicBarrier barrier new CyclicBarrier(4, this::aggregateResults); for (int i 0; i 4; i) { executor.submit(() - { while (round MAX_ROUNDS) { computePartialResult(); barrier.await(); // 同步进入下一轮 round; } }); }底层原理CyclicBarrier不基于 AQS而是使用ReentrantLockCondition实现Condition 原理详见Java并发编程Lock原理详解每次调用await()线程进入条件队列等待。当最后一个线程到达时唤醒所有等待线程并执行barrierAction如有。完成后自动重置计数器支持重复使用。若某个线程在等待期间被中断或超时屏障将进入“损坏”broken状态后续调用会抛出BrokenBarrierException。CyclicBarrier 与 CountDownLatch 的区别特性CountDownLatchCyclicBarrier控制方向一方等待多方所有线程互相等待是否可重用❌✅是否支持回调❌✅barrierAction底层实现AQSReentrantLock ConditionPhaserJDK 7灵活的阶段同步器Phaser新增于 JDK 7是对CyclicBarrier和CountDownLatch的强大扩展支持动态注册参与者、多阶段同步和分层结构适用于更复杂的并发协调场景。使用场景多阶段并行任务如 Map-Reduce 的 map → shuffle → reduce。动态增减工作线程例如任务中途加入新 worker。大规模并行计算中需要分组同步通过分层 Phaser 实现。替代多个CyclicBarrier或CountDownLatch的组合逻辑。核心 API// 构造方法 public Phaser(); // 无初始参与者 public Phaser(int parties); // 指定初始参与者数量 public Phaser(Phaser parent); // 构建父子分层结构 // 核心方法 public int register(); // 注册一个新参与者返回当前阶段号 public int arrive(); // 到达屏障不等待 public int arriveAndAwaitAdvance(); // 到达并等待其他参与者 public int arriveAndDeregister(); // 到达并注销自己退出后续阶段 public boolean isTerminated(); // 是否已终止当参与者数为0时终止使用示例动态多阶段任务public class PhaserExample { public static void main(String[] args) { Phaser phaser new Phaser(0); // 初始无参与者 // 启动3个任务线程 for (int i 0; i 3; i) { phaser.register(); // 注册参与者 new Thread(() - { try { for (int phase 0; phase 3; phase) { System.out.println(Thread.currentThread().getName() 完成阶段 phase); // 到达屏障并等待其他线程 phaser.arriveAndAwaitAdvance(); } // 任务结束注销自己 phaser.arriveAndDeregister(); } catch (Exception e) { e.printStackTrace(); } }).start(); } // 主线程等待所有阶段完成 while (!phaser.isTerminated()) { Thread.yield(); } System.out.println(所有阶段已完成); } }输出Thread-1 完成阶段 0 Thread-2 完成阶段 0 Thread-0 完成阶段 0 Thread-0 完成阶段 1 Thread-2 完成阶段 1 Thread-1 完成阶段 1 Thread-2 完成阶段 2 Thread-1 完成阶段 2 Thread-0 完成阶段 2 所有阶段已完成高级特性分层 Phaser当参与者数量极大如数千线程时单一Phaser的同步开销会很高。此时可构建树状分层结构Phaser root new Phaser(); Phaser group1 new Phaser(root); // 子 Phaser父为 root Phaser group2 new Phaser(root); // group1 内部线程只与同组同步最终由 root 汇总 group1.register(); new Thread(() - { group1.arriveAndAwaitAdvance(); // 仅与 group1 同步 }).start();这种结构能显著减少锁竞争提升大规模并发性能。、应用场景示例分阶段并行处理// 模拟三阶段数据处理加载 → 转换 → 输出 Phaser phaser new Phaser(0); ListThread workers IntStream.range(0, 4) .mapToObj(i - { phaser.register(); return new Thread(() - { load(); phaser.arriveAndAwaitAdvance(); transform(); phaser.arriveAndAwaitAdvance(); output(); phaser.arriveAndAwaitAdvance(); phaser.arriveAndDeregister(); }); }) .peek(Thread::start) .collect(Collectors.toList()); // 等待全部完成 while (!phaser.isTerminated()) { Thread.yield(); }底层原理不同于CountDownLatch和SemaphorePhaser未基于 AQS而是自行实现同步机制它的实现融合了自旋锁 队列管理状态字段使用一个long类型的state字段高位存阶段号phase低位存参与者数量parties。自适应等待策略参与者少时使用自旋等待低延迟。参与者多或等待时间长时自动切换到阻塞队列节省 CPU。Phaser 与 CyclicBarrier 的对比特性CyclicBarrierPhaser引入版本JDK 1.5JDK 1.7是否可重用✅自动重置✅阶段递增动态增减参与者❌✅register() / arriveAndDeregister()分层支持❌✅父子结构阶段号追踪❌✅getPhase()终止机制损坏即不可用参与者归零后优雅终止性能大规模较差全局锁更优分层 自适应等待使用建议若参与者数量固定且较少用CyclicBarrier即可。若需动态调整、多阶段、大规模则优先选择Phaser。SemaphoreJDK 5信号量使用场景Semaphore用于控制同时访问特定资源的线程数量比如数据库连接池最多 N 个连接。接口限流如每秒最多处理 100 个请求。模拟有限资源的分配如停车场车位。new Semaphore(1)实际上等价于synchronized或ReentrantLock。核心 APIpublic Semaphore(int permits); public Semaphore(int permits, boolean fair); // 公平/非公平模式 public void acquire() throws InterruptedException; public void release(); public boolean tryAcquire(); // 非阻塞尝试获取使用示例public class SemaphoreExample { private static final Semaphore semaphore new Semaphore(2); // 最多2个线程并发 public static void main(String[] args) { for (int i 0; i 5; i) { new Thread(() - { try { semaphore.acquire(); System.out.println(Thread.currentThread().getName() 获取许可正在执行...); Thread.sleep(2000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { semaphore.release(); System.out.println(Thread.currentThread().getName() 释放许可); } }).start(); } } }输出Thread-0 获取许可正在执行... Thread-1 获取许可正在执行... Thread-0 释放许可 Thread-2 获取许可正在执行... Thread-1 释放许可 Thread-3 获取许可正在执行... Thread-2 释放许可 Thread-3 释放许可 Thread-4 获取许可正在执行... Thread-4 释放许可应用场景示例API 限流private final Semaphore rateLimiter new Semaphore(100); // 每秒最多100请求 public void handleRequest() { if (rateLimiter.tryAcquire()) { try { process(); } finally { rateLimiter.release(); } } else { throw new RuntimeException(请求过于频繁); } }底层原理同样基于AQSAQS 原理详见Java并发编程Lock原理详解state表示可用许可数量。acquire()尝试减少state若不足则入队等待。release()增加state并唤醒等待线程。支持公平模式按请求顺序分配许可。ExchangerJDK 5数据交换器使用场景Exchanger专为两个线程之间交换数据而设计典型场景如双缓冲机制一个线程写入缓冲区 A另一个写入 B满后交换。生产者与消费者高效传递中间结果。日志收集器中交换日志缓冲区。核心 APIpublic V exchange(V x) throws InterruptedException; public V exchange(V x, long timeout, TimeUnit unit) throws ...;示例代码public class ExchangerExample { public static void main(String[] args) { ExchangerString exchanger new Exchanger(); new Thread(() - { try { String data Thread-A 的数据; System.out.println(A 准备交换: data); String received exchanger.exchange(data); System.out.println(A 收到: received); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); new Thread(() - { try { Thread.sleep(1000); // 模拟延迟 String data Thread-B 的数据; System.out.println(B 准备交换: data); String received exchanger.exchange(data); System.out.println(B 收到: received); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }).start(); } }输出A 准备交换: Thread-A 的数据 B 准备交换: Thread-B 的数据 B 收到: Thread-A 的数据 A 收到: Thread-B 的数据应用场景示例双缓冲日志ExchangerListLogEntry exchanger new Exchanger(); ListLogEntry bufferA new ArrayList(1000); ListLogEntry bufferB new ArrayList(1000); // 写线程不断填充 bufferA // 写满后与读线程交换读线程异步刷盘底层原理Exchanger内部使用Slot 或 Node 结构暂存数据通过CAS 自旋实现高效交换第一个调用exchange()的线程将数据放入槽位并等待。第二个线程到来后取出对方数据放入自己的数据完成交换。若超时或中断会清理槽位并抛出异常。注意仅支持两个线程配对交换第三个线程调用exchange()会一直阻塞直到有新的配对。工具类对比总结特性CountDownLatchCyclicBarrierPhaserSemaphoreExchanger引入版本1.51.51.71.51.5是否可重用❌✅✅✅✅协作模式一方等多方所有互相等多阶段动态同步控制并发数两线程交换动态参与者❌❌✅❌❌分层支持❌❌✅❌❌底层机制AQSReentrantLockCondition自定义同步CAS自旋队列AQSCAS自旋典型用途初始化等待分阶段计算复杂并行任务协调限流数据交换