主页 > 软件开发  > 

详解CountDownlatch

详解CountDownlatch
引言

CountDownLatch 是 Java 并发包 java.util.concurrent 中的一个同步工具类,由著名的并发编程大师 Doug Lea 所开发。它允许一个或多个线程等待其他线程完成操作后再继续执行,其核心思想是通过一个计数器,对计数器进行调度来实现

原理

CountDownLatch 初始化时会设置一个计数器的值,该值表示需要等待完成的操作数量。每当一个线程完成了自己的任务后,会调用 countDown() 方法将计数器减 1。当计数器的值变为 0 时,意味着所有需要等待的操作都已完成,此时在 await() 方法上等待的线程将被唤醒,继续执行后续操作。

源码分析

内部类

private final Sync sync; private static final class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 4982264981922014374L; Sync(int count) { setState(count); } int getCount() { return getState(); } protected int tryAcquireShared(int acquires) { return (getState() == 0) ? 1 : -1; } protected boolean tryReleaseShared(int releases) { // Decrement count; signal when transition to zero for (;;) { int c = getState(); if (c == 0) return false; int nextc = c-1; if (compareAndSetState(c, nextc)) return nextc == 0; } } } sync:CountDownLatch 内部使用 Sync 类的实例,Sync 继自 AbstractQueuedSynchronizer(AQS),借助 AQS 的状态(state)来表示计数器的值。Sync 类: 构造函数 Sync(int count):在创建 Sync 实例时,会调用 setState(count) 方法将 AQS 的状态初始化为传入的计数器值。getCount() 方法:返回 AQS 的当前状态,即计数器的当前值。tryAcquireShared(int acquires) 方法:用于尝试以共享模式获取锁。当计数器值为 0 时返回 1,表示可以获取锁;否则返回 -1,表示无法获取锁。tryReleaseShared(int releases) 方法:用于尝试以共享模式释放锁。使用 for(;;) 无限循环结合 compareAndSetState 方法(CAS 操作)来安全地将计数器减 1。当计数器减为 0 时返回 true,表示释放成功且可以唤醒等待线程;否则返回 false。

结合源码我们一般是主线程设计为等待线程,线程池去完成计数器的增减

内部方法

await()

public void await() throws InterruptedException { sync.acquireSharedInterruptibly(1); } await() 方法会调用 sync 的 acquireSharedInterruptibly(1) 方法,该方法是 AQS 提供的以共享模式获取锁的可中断方法。其具体逻辑为:

检查当前线程是否被中断,若被中断则抛出 InterruptedException 异常。

调用 tryAcquireShared 方法尝试获取锁,若计数器为 0 则获取成功,线程继续执行;否则将当前线程放入等待队列并阻塞。

await(long timeout, TimeUnit unit) 

public boolean await(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); }

该方法允许线程等待指定的时间。调用 sync 的 tryAcquireSharedNanos(1, unit.toNanos(timeout)) 方法,在指定时间内尝试以共享模式获取锁。若在超时时间内计数器变为 0 则返回 true;若超时则返回 false。

countDown() 

countDown() 方法调用 sync 的 releaseShared(1) 方法,以共享模式释放锁。该方法会调用 tryReleaseShared 方法尝试将计数器减 1,若减为 0 则唤醒所有在等待队列中的线程。

实战

下面是多线程实战CountDownlatch,依旧是主线程等待,在循环中创建线程调用await方法

import java.util.concurrent.CountDownLatch; public class CountDownLatchExample { public static void main(String[] args) throws InterruptedException { // 创建一个 CountDownLatch 实例,计数器初始值为 3 CountDownLatch latch = new CountDownLatch(3); // 创建并启动三个工作线程 for (int i = 0; i < 3; i++) { final int workerId = i; new Thread(() -> { try { System.out.println("Worker " + workerId + " is working."); // 模拟工作 Thread.sleep((long) (Math.random() * 1000)); System.out.println("Worker " + workerId + " has finished."); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 工作完成,计数器减 1 latch.countDown(); } }).start(); } // 主线程等待所有工作线程完成 System.out.println("Main thread is waiting for workers to finish."); latch.await(); System.out.println("All workers have finished. Main thread can continue."); } }

标签:

详解CountDownlatch由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“详解CountDownlatch