Learning Java Concurrency - CountDownLatch
CountDownLatch 是一种比较有意思的线程同步方法,主要用于需要同步启动的环境中。
举个栗子,部门进行聚餐要等到大家都到齐了才能开动。这个时候CountDownLatch可以理解为“还有多少人没有到”这个东西,来了一个,这个东西的值就会减1。一直到人都到齐了,这个东西的值变为了0,也就是可以开吃了。
举个栗子,通用的make进行多工程代码编译,必须所有工程编译完了才能结束。
举个栗子,项目上线,各个模块都上线完了,leader说一句OK,大家才能走。
要注意以上几个栗子都是每个线程减1,但是实际中具体减多少不做限制。
比如,猫有9条命,两个人你一下我一下一刀一刀砍上去,然后它就死了。这个也可用CountDownLatch来描述。
🔗CountDownLatch 的简单使用
首先,估计要参与工作的子工作数,创建一个CountDownLatch。
然后,创建干活的线程,持有该CountDownLatch实例,调用await()等待事件。比如具体到聚餐就是“开吃”,具体到9命猫就是“命没了要死了”。
然后,创建多个准备的线程,每个线程持有相同的CountDownLatch实例。这些线程用来做准备工作,争取早日达到能干活的状态。具体到聚餐上就是“人一个一个来”,具体到猫上就是“一次一次被砍死”。
然后,就结束了。
🔗CountDownLatch 的 API
CountDownLatch(int)
构造一个可以由n个线程共享的闭锁。void await() throws InterruptedException
等待原始的n变成0。调用的线程会被阻塞,直到条件达到。boolean await(long timeout, TimeUnit unit) throws InterruptedException
等待原始的n变成0。调用的线程会被阻塞,直到条件达到(return true)或者超时(return false)。void countDown()
n - 1。long getCount()
查询n的值。
CountDownLatch内部有一个静态类Sync。CountDownLatch的所有方法都委托到内部一个Sync实例。
private static final class Sync extends AbstractQueuedSynchronizer
Sync可以理解为一个共享锁,主要使用AbstractQueuedSynchronizer的共享锁方面的功能。
🔗示例代码
package me.wbprime.showcase.concurrent; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Class: CountDownLatchCase * Date: 2016/03/30 13:05 */ public final class CountDownLatchCase { public static class Module implements Runnable { private CountDownLatch latch; private String name; public Module(final String name, final CountDownLatch val) { this.name = (null != name) ? name : "Anonymous"; this.latch = val; } public void run() { System.out.println("Begin to deploy module: " + name); final Random rnd = new Random(System.currentTimeMillis()); final int sleepTime = rnd.nextInt(1000) + 1; try { Thread.sleep(sleepTime); } catch (InterruptedException e) { // do nothing } System.out.println("Finish deploying module: " + name); latch.countDown(); } } public static class Controller implements Runnable { private CountDownLatch latch; public Controller(final CountDownLatch val) { this.latch = val; } public void run() { try { latch.await(); System.out.println("Finish deploying all modules"); } catch (InterruptedException e) { // do nothing } } } public static void main(String[] args) { final int moduleCount = 20; final CountDownLatch syncLatch = new CountDownLatch(moduleCount); final ExecutorService executorService = Executors.newFixedThreadPool(8); executorService.execute(new Controller(syncLatch)); for (int i = 0; i < moduleCount; i++) { executorService.execute(new Module("Module " + i, syncLatch)); } executorService.shutdown(); } }
🔗示例代码说明
-
有一个项目需要上线。项目的各个子模块解耦合做的非常好,彼此可以独立上线。但是由于上线有BOSS看着,所以所有模块的团队不管上没上线完,都得在公司里呆着,防止出意外。
-
Controller 类表征一个上线通知。所有模块上线完了,整个项目才算上线完了。BOSS才发话,大家才可以回家。
-
Module 类表征一个一个的模块。各个模块自己独立上线,上线完了通知项目组一声,然后等别的模块上线。
-
main函数里面,创建了CountDownLatch实例,创建了项目组,创建了各个模块,然后大家一起等上线。