CountDownLatch
CountDownLatch一般用于一个线程等待多个线程完成操作,
@Slf4j
public class CountDownLatchExample1 {
private final static int threadCount = 200;
// private static Logger log = LoggerFactory.getLogger(CountDownLatchExample1.class);
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
executorService.execute(
()->{
try {
test(threadNum);
}
catch (Exception e){
log.error("exception",e);
}
finally {
countDownLatch.countDown();
}
}
);
}
countDownLatch.await();
log.info("finish");
executorService.shutdown();
}
private static void test(int threadNum) throws Exception {
Thread.sleep(100);
log.info("{}", threadNum);
Thread.sleep(100);
}
}
这里的主线程将等待200个工作线程都完成工作后再继续执行,并关闭线程池。
CyclicBarrier
CyclicBarrier用于多个线程都到达某个状态后,所有等待线程再继续执行。CyclicBarrier可以用于多线程计算数据,最后合并计算结果的场景。例如,用一个Excel保存了用户所有银行流水,每个Sheet保存一个账户近一年的每笔银行流水,现在需要统计用户的日均银行流水,先用多个线程处理每个sheet里的银行流水,都执行完之后,得到每个sheet的日均银行流水,最后,再用barrierAction用这些线程的计算结果,计算出整个Excel的日均银行流水。
public class BankWaterService implements Runnable{
private CyclicBarrier barrier = new CyclicBarrier(4,this);
private CountDownLatch countDownLatch = new CountDownLatch(4);
private ExecutorService threadPool = Executors.newFixedThreadPool(4);
private ConcurrentHashMap<String,Integer> sheetBankCount = new ConcurrentHashMap<>();
public void count() throws InterruptedException {
for (int i = 0; i <4 ; i++) {
threadPool.execute(()->{
sheetBankCount.put(Thread.currentThread().getName(),1);
try {
System.out.println(Thread.currentThread().getName()+" wait");
barrier.await();
System.out.println(Thread.currentThread().getName()+" continue " + "final result: "+sheetBankCount.get("result"));
countDownLatch.countDown();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
});
}
countDownLatch.await();
threadPool.shutdown();
}
@Override
public void run() {
int sum = 0;
for (Map.Entry<String,Integer> entry:sheetBankCount.entrySet()){
sum+= entry.getValue();
}
sheetBankCount.put("result",sum);
System.out.println("result: "+sum);
}
public static void main(String[] args) throws InterruptedException {
BankWaterService bankWaterService = new BankWaterService();
bankWaterService.count();
}
}
这里每一个工作线程将自己的计算结果放入ConcurrentHashMap中就进入等待,当所有工作线程都进入等待后,CyclicBarrier到达屏障,将调用回调方法,这里的回调方法就是this的run方法。之后所有工作线程被唤醒。CountDownLatch用于等待所有工作线程结束后关闭线程池。
"C:\Program Files\Java\jdk1.8.0_221\bin\java.exe" "-javaagent:C:\Development\Intellij Idea\IntelliJ IDEA 2018.2.8\lib\idea_rt.jar=55458:C:\Development\Intellij Idea\IntelliJ IDEA 2018.2.8\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_221\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_221\jre\lib\rt.jar;C:\Development\java projects\Concurrency\target\classes;C:\Development\maven\Repo\org\springframework\boot\spring-boot-starter-web\1.5.9.RELEASE\spring-boot-starter-web-1.5.9.RELEASE.jar;C:\Development\maven\Repo\org\springframework\boot\spring-boot-starter\1.5.9.RELEASE\spring-boot-starter-1.5.9.RELEASE.jar;C:\Development\maven\Repo\org\springframework\boot\spring-boot\1.5.9.RELEASE\spring-boot-1.5.9.RELEASE.jar;C:\Development\maven\Repo\org\springframework\boot\spring-boot-autoconfigure\1.5.9.RELEASE\spring-boot-autoconfigure-1.5.9.RELEASE.jar;C:\Development\maven\Repo\org\springframework\boot\spring-boot-starter-logging\1.5.9.RELEASE\spring-boot-starter-logging-1.5.9.RELEASE.jar;C:\Development\maven\Repo\ch\qos\logback\logback-classic\1.1.11\logback-classic-1.1.11.jar;C:\Development\maven\Repo\ch\qos\logback\logback-core\1.1.11\logback-core-1.1.11.jar;C:\Development\maven\Repo\org\slf4j\jcl-over-slf4j\1.7.25\jcl-over-slf4j-1.7.25.jar;C:\Development\maven\Repo\org\slf4j\jul-to-slf4j\1.7.25\jul-to-slf4j-1.7.25.jar;C:\Development\maven\Repo\org\slf4j\log4j-over-slf4j\1.7.25\log4j-over-slf4j-1.7.25.jar;C:\Development\maven\Repo\org\yaml\snakeyaml\1.17\snakeyaml-1.17.jar;C:\Development\maven\Repo\org\springframework\boot\spring-boot-starter-tomcat\1.5.9.RELEASE\spring-boot-starter-tomcat-1.5.9.RELEASE.jar;C:\Development\maven\Repo\org\apache\tomcat\embed\tomcat-embed-core\8.5.23\tomcat-embed-core-8.5.23.jar;C:\Development\maven\Repo\org\apache\tomcat\tomcat-annotations-api\8.5.23\tomcat-annotations-api-8.5.23.jar;C:\Development\maven\Repo\org\apache\tomcat\embed\tomcat-embed-el\8.5.23\tomcat-embed-el-8.5.23.jar;C:\Development\maven\Repo\org\apache\tomcat\embed\tomcat-embed-websocket\8.5.23\tomcat-embed-websocket-8.5.23.jar;C:\Development\maven\Repo\org\hibernate\hibernate-validator\5.3.6.Final\hibernate-validator-5.3.6.Final.jar;C:\Development\maven\Repo\javax\validation\validation-api\1.1.0.Final\validation-api-1.1.0.Final.jar;C:\Development\maven\Repo\org\jboss\logging\jboss-logging\3.3.1.Final\jboss-logging-3.3.1.Final.jar;C:\Development\maven\Repo\com\fasterxml\classmate\1.3.4\classmate-1.3.4.jar;C:\Development\maven\Repo\com\fasterxml\jackson\core\jackson-databind\2.8.10\jackson-databind-2.8.10.jar;C:\Development\maven\Repo\com\fasterxml\jackson\core\jackson-annotations\2.8.0\jackson-annotations-2.8.0.jar;C:\Development\maven\Repo\com\fasterxml\jackson\core\jackson-core\2.8.10\jackson-core-2.8.10.jar;C:\Development\maven\Repo\org\springframework\spring-web\4.3.13.RELEASE\spring-web-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\springframework\spring-aop\4.3.13.RELEASE\spring-aop-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\springframework\spring-beans\4.3.13.RELEASE\spring-beans-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\springframework\spring-context\4.3.13.RELEASE\spring-context-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\springframework\spring-webmvc\4.3.13.RELEASE\spring-webmvc-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\springframework\spring-expression\4.3.13.RELEASE\spring-expression-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\slf4j\slf4j-api\1.7.25\slf4j-api-1.7.25.jar;C:\Development\maven\Repo\org\springframework\spring-core\4.3.13.RELEASE\spring-core-4.3.13.RELEASE.jar;C:\Development\maven\Repo\org\projectlombok\lombok\1.16.10\lombok-1.16.10.jar;C:\Development\maven\Repo\com\google\guava\guava\23.0\guava-23.0.jar;C:\Development\maven\Repo\com\google\code\findbugs\jsr305\1.3.9\jsr305-1.3.9.jar;C:\Development\maven\Repo\com\google\errorprone\error_prone_annotations\2.0.18\error_prone_annotations-2.0.18.jar;C:\Development\maven\Repo\com\google\j2objc\j2objc-annotations\1.1\j2objc-annotations-1.1.jar;C:\Development\maven\Repo\org\codehaus\mojo\animal-sniffer-annotations\1.14\animal-sniffer-annotations-1.14.jar;C:\Development\maven\Repo\joda-time\joda-time\2.9\joda-time-2.9.jar;C:\Development\maven\Repo\redis\clients\jedis\2.8.2\jedis-2.8.2.jar;C:\Development\maven\Repo\org\apache\commons\commons-pool2\2.4.3\commons-pool2-2.4.3.jar" com.mmall.concurrency.threadTest.cyclicBarrier.BankWaterService
pool-1-thread-1 wait
pool-1-thread-4 wait
pool-1-thread-2 wait
pool-1-thread-3 wait
result: 4
pool-1-thread-3 continue final result: 4
pool-1-thread-1 continue final result: 4
pool-1-thread-4 continue final result: 4
pool-1-thread-2 continue final result: 4
Process finished with exit code 0
可以看到每个工作线程完成自己的计算任务,把它加入到ConcurrentHashMap后就进入等待,等4个工作线程都到达屏障后,调用回调方法,再唤醒所有线程。最后关闭线程池。