Java并发 - CountDownLatch详解
CountDownLatch是什么?CountDownLatch的作用?
CountDownLatch适用于什么场景?
1. CountDownLatch介绍
CountDownLatch 是 Java 中的一个同步工具类,它允许一个或多个线程等待其他线程完成操作。CountDownLatch 的主要思想是,一个线程等待其他线程完成一组操作,它在倒计时计数器的基础上工作,计数器的初始值是一个正整数,每当一个线程完成一项操作,计数器的值减一。当计数器的值变为零时,等待的线程被释放,可以继续执行。
2. CountDownLatch源码解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| 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.acquireSharedInterruptibly(1); } public boolean await(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); } public void countDown() { sync.releaseShared(1); } public long getCount() { return sync.getCount(); } }
|
Sync类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| 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) { for (;;) { int c = getState(); if (c == 0) return false; int nextc = c-1; if (compareAndSetState(c, nextc)) return nextc == 0; } } }
|
3. CountDownLatch应用场景
- 多线程任务协同:
CountDownLatch 可以用于多个线程协同完成某项任务。一个主线程等待其他多个线程完成任务,每个子线程完成一部分工作后调用 countDown() 方法减少计数值,主线程通过 await() 方法等待计数值变为零。
- 并行任务的性能测试: 可以用
CountDownLatch 来测量并行任务的性能,主线程可以等待多个并行任务同时开始执行。
- 等待多个服务初始化完成: 在系统启动时,有时需要等待多个服务初始化完成后再继续执行。每个服务初始化完成后调用
countDown()。
- 分布式系统中的协同: 在分布式系统中,
CountDownLatch 可以用于等待多个节点的某个事件的发生,以协同分布式系统的操作。
4. CountDownLatch示例
模拟拼团活动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| 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<>();
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(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| 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'
|