Java并发 - CountDownLatch详解

CountDownLatch是什么?CountDownLatch的作用?

CountDownLatch适用于什么场景?

1. CountDownLatch介绍

CountDownLatch 是 Java 中的一个同步工具类,它允许一个或多个线程等待其他线程完成操作。CountDownLatch 的主要思想是,一个线程等待其他线程完成一组操作,它在倒计时计数器的基础上工作,计数器的初始值是一个正整数,每当一个线程完成一项操作,计数器的值减一。当计数器的值变为零时,等待的线程被释放,可以继续执行。

2. CountDownLatch源码解析

public class CountDownLatch {
    // 构造方法
    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }
	// 用于阻塞当前线程,直到计数器的值变为零
    public void await() throws InterruptedException {
        // 在 Sync 类中实现,用于尝试获取共享许可,如果计数器为零,则直接返回,否则会进入等待队列等待。
        sync.acquireSharedInterruptibly(1);
    }
    // 用于等待一段时间,超时后返回
    public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
        // 用于尝试在规定的时间内获取共享许可,如果在超时前获取到许可则返回 true,否则返回 false。
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }
    // 用于将计数器的值减一,表示有一个线程完成了一项操作
    public void countDown() {
        // 在 Sync 类中实现,用于释放共享许可
        sync.releaseShared(1);
    }
	// 用于获取当前计数器的值
    public long getCount() {
        // 返回当前的计数值
        return sync.getCount();
    }
}

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;
        }
    }
}

3. CountDownLatch应用场景

  1. 多线程任务协同: CountDownLatch 可以用于多个线程协同完成某项任务。一个主线程等待其他多个线程完成任务,每个子线程完成一部分工作后调用 countDown() 方法减少计数值,主线程通过 await() 方法等待计数值变为零。
  2. 并行任务的性能测试: 可以用 CountDownLatch 来测量并行任务的性能,主线程可以等待多个并行任务同时开始执行。
  3. 等待多个服务初始化完成: 在系统启动时,有时需要等待多个服务初始化完成后再继续执行。每个服务初始化完成后调用 countDown()
  4. 分布式系统中的协同: 在分布式系统中,CountDownLatch 可以用于等待多个节点的某个事件的发生,以协同分布式系统的操作。

4. CountDownLatch示例

模拟拼团活动

public class CountDownLatchDemo {

    public static void main(String[] args) {
        pt();
    }

    private static void pt() {
        // 模拟拼团活动
        final CountDownLatch countDownLatch = new CountDownLatch(10);
        List<String> ids = new ArrayList<>();

        // 目前有10个人进行拼团
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                if (countDownLatch.getCount() > 0) {
                    synchronized (ids) {
                        if (countDownLatch.getCount() > 0) {
                            ids.add(Thread.currentThread().getName());
                            System.out.println(Thread.currentThread().getName() + "拼团成功!!!");
                            countDownLatch.countDown();
                        }
                    }
                }
                System.out.println(Thread.currentThread().getName() + "请求拼团!!!商品剩余" + countDownLatch.getCount());
            }, String.valueOf(i + 1)).start();
        }

        new Thread(() -> {
            try {
                countDownLatch.await();
                System.out.println("拼团结束============================================================");
                System.out.println("拼团人员id"+ids);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }, "拼团").start();
    }
}
Connected to the target VM, address: '127.0.0.1:54442', transport: 'socket'
1拼团成功!!!
1请求拼团!!!商品剩余9
4拼团成功!!!
4请求拼团!!!商品剩余8
8拼团成功!!!
8请求拼团!!!商品剩余7
6拼团成功!!!
14拼团成功!!!
6请求拼团!!!商品剩余6
5拼团成功!!!
5请求拼团!!!商品剩余4
14请求拼团!!!商品剩余5
7拼团成功!!!
7请求拼团!!!商品剩余3
3拼团成功!!!
3请求拼团!!!商品剩余2
2拼团成功!!!
22拼团成功!!!
2请求拼团!!!商品剩余1
19请求拼团!!!商品剩余0
24请求拼团!!!商品剩余0
13请求拼团!!!商品剩余0
25请求拼团!!!商品剩余0
9请求拼团!!!商品剩余0
20请求拼团!!!商品剩余0
28请求拼团!!!商品剩余0
22请求拼团!!!商品剩余0
30请求拼团!!!商品剩余0
21请求拼团!!!商品剩余0
27请求拼团!!!商品剩余0
17请求拼团!!!商品剩余0
11请求拼团!!!商品剩余0
10请求拼团!!!商品剩余0
12请求拼团!!!商品剩余0
15请求拼团!!!商品剩余0
23请求拼团!!!商品剩余0
16请求拼团!!!商品剩余0
18请求拼团!!!商品剩余0
拼团结束============================================================
26请求拼团!!!商品剩余0
29请求拼团!!!商品剩余0
拼团人员id[1, 4, 8, 6, 14, 5, 7, 3, 2, 22]
Disconnected from the target VM, address: '127.0.0.1:54442', transport: 'socket'
`CountDownLatch` 是 Java 中的一个并发工具类,用于实现线程之间的等待和协调。它通常用于一个或多个线程等待其他线程完成某项操作后再继续执行。 `CountDownLatch` 的工作原理是通过一个计数器来实现的。创建 `CountDownLatch` 实例时需要指定计数器的初始值,该值表示需要等待的线程数量。当一个线程完成了某个操作后,可以调用 `countDown()` 方法将计数器减一。其他线程可以通过调用 `await()` 方法来等待计数器达到零,一旦计数器变为零,所有等待的线程将被唤醒,继续执行。 下面是 `CountDownLatch` 的基本用法示例: ```java import java.util.concurrent.CountDownLatch; public class Example { public static void main(String[] args) throws InterruptedException { int threadCount = 5; CountDownLatch latch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) { Thread thread = new Thread(() -> { // 线程执行某个操作 // ... // 操作完成后调用 countDown() latch.countDown(); }); thread.start(); } // 等待所有线程完成操作 latch.await(); // 所有线程完成后继续执行 System.out.println("All threads have finished their operations."); } } ``` 在上面的示例中,创建了一个包含 5 个线程的 `CountDownLatch` 对象。每个线程执行某个操作后调用 `countDown()` 方法,然后主线程调用 `await()` 方法等待所有线程完成。一旦计数器变为零,主线程继续执行并输出提示信息。 希望这个简单的示例能帮助你了解 `CountDownLatch` 的用法。如果有任何疑问,请随时提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

--土拨鼠--

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值