定义
CountDownLatch是juc下的一个多线程锁,下面是jdk对它的定义
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
翻译如下
一种同步辅助工具,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。
可以简单地理解为倒计次数锁,只有计数为零时,才能执行之后的代码
关键api
- 构造方法
public CountDownLatch(int count)
- 倒计数。每执行一次这个方法,计数就减少一次
public void countDown()
- 等待。阻塞方法,如果倒计次数没有清空,则会一直阻塞,后面的代码则无法执行
public void await() throws InterruptedException
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException
- 获取当前计数
public long getCount()
应用场景
有一个物业经理,派出手下11个员工去收取物业费,每个员工收费结束交给经理,经理计算手中的总额,大于等于100元,则把交给上级。最后的员工到达后,不论多少,经理都将手中的钱交给上级
EMPLOYEE_COUNT :员工数量
totalAmount :经理手中的金额
THRESHOLD_AMOUNT:门槛金额,当到达门槛金额时,要执行上交操作,totalAmount 清零
feeQueue :使用BlockingQueue阻塞队列用于存放收取的物业费
代码如下
private static final int EMPLOYEE_COUNT = 11;
private static final int THRESHOLD_AMOUNT = 100;
private static BlockingQueue<Integer> feeQueue = new ArrayBlockingQueue<>(EMPLOYEE_COUNT);
private static AtomicInteger totalAmount = new AtomicInteger(0);
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(EMPLOYEE_COUNT + 1);
CountDownLatch countDownLatch = new CountDownLatch(EMPLOYEE_COUNT);
// 启动经理线程
executorService.execute(() -> {
try {
while (countDownLatch.getCount() > 0 || !feeQueue.isEmpty()) {
Integer amount = feeQueue.poll();
if (amount != null) {
int currentAmount = totalAmount.addAndGet(amount);
System.out.println("经理收到了 " + amount + " 元,总金额:" + currentAmount);
if (currentAmount >= THRESHOLD_AMOUNT) {
System.out.println("经理将 " + currentAmount + " 元交给上级");
totalAmount.set(0);
}
}
}
} catch (Exception e) {
Thread.currentThread().interrupt();
}
});
// 启动员工线程
for (int i = 1; i <= EMPLOYEE_COUNT; i++) {
final int employeeId = i;
executorService.execute(() -> {
int amount = (int) (Math.random() * 100) + 1; // 模拟收取随机金额
System.out.println("员工 " + employeeId + " 收取了 " + amount + " 元");
try {
Thread.sleep(300);
feeQueue.put(amount);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
countDownLatch.countDown();
});
}
// 关闭线程池
executorService.shutdown();
try {
countDownLatch.await(); // 等待所有员工线程完成
if (executorService.awaitTermination(20, TimeUnit.SECONDS)) {
System.out.println("线程执行完毕");
} else {
System.out.println("线程超时");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 最后处理剩余金额
int currentAmount = totalAmount.get();
if (currentAmount > 0) {
System.out.println("最后的员工到达后,经理将剩余的 " + currentAmount + " 元交给上级");
}
}
输出结果如下
可以看到经理每收取100元就上交一次,最后的员工到达后,经理将剩余的钱上交了,符合预期
员工 11 收取了 29 元
员工 4 收取了 73 元
员工 6 收取了 54 元
员工 5 收取了 94 元
员工 3 收取了 19 元
员工 9 收取了 44 元
员工 1 收取了 57 元
员工 8 收取了 92 元
员工 7 收取了 23 元
员工 2 收取了 83 元
员工 10 收取了 18 元
经理收到了 19 元,总金额:19
经理收到了 29 元,总金额:48
经理收到了 23 元,总金额:71
经理收到了 92 元,总金额:163
经理将 19+29+23+92=163 元交给上级
经理收到了 44 元,总金额:44
经理收到了 73 元,总金额:117
经理将 44+73=117 元交给上级
经理收到了 18 元,总金额:18
经理收到了 83 元,总金额:101
经理将 18+83=101 元交给上级
经理收到了 57 元,总金额:57
经理收到了 94 元,总金额:151
经理将 57+94=151 元交给上级
经理收到了 54 元,总金额:54
线程执行完毕
最后的员工到达后,经理将剩余的 54 元交给上级