Concurrent同步工具类01 - CountDownLatch

CountDownLatch介绍

java.util.concurrent.CountDownLatch,我们可以把它看作一个计数器,只不过这个计数器的操作是原子操作,同时只能有一个线程去操作这个计数器,也就是同时只能有一个线程去减这个计数器里面的值。

可以为CountDownLatch对象设置一个初始的数字作为计数值,任何调用这个对象上的await()方法都会阻塞,直到这个计数器的计数值被其他的线程减为0为止。

应用场景

CountDownLatch的一个非常典型的应用场景是:有一个任务A想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如想要继续往下执行的任务A调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务A将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。CountDownLatch 以一个给定的数量初始化。countDown() 每被调用一次,这 一数量就减一。

举例:

假设有老板和3个工人的雇佣关系,只有等3个工人的工作完成以后,老板才会结束工作完成情况的检查。

Concurrent同步工具类01 -  CountDownLatch
 1 package com.test.lesson01;
 2 
 3 import java.util.concurrent.CountDownLatch;
 4 import java.util.concurrent.ExecutorService;
 5 import java.util.concurrent.Executors;
 6 
 7 public class Demo3 {
 8     public static void main(String[] args) {
 9         ExecutorService executorService= Executors.newFixedThreadPool(4);
10         CountDownLatch countDownLatch=new CountDownLatch(3);
11         Worker worker1=new Worker(countDownLatch,"w1");
12         Worker worker2=new Worker(countDownLatch,"w2");
13         Worker worker3=new Worker(countDownLatch,"w3");
14         Boss boss=new Boss(countDownLatch);
15         executorService.execute(worker1);
16         executorService.execute(worker2);
17         executorService.execute(worker3);
18         executorService.execute(boss);
19         executorService.shutdown();
20     }
21 }
22 
23 
24 
25 class Worker implements Runnable{
26     private CountDownLatch countDownLatch;
27     private String name;
28     public Worker(CountDownLatch countDownLatch,String name){
29         this.countDownLatch=countDownLatch;
30         this.name=name;
31     }
32 
33     @Override
34     public void run() {
35         try{
36             Thread.sleep(1000);
37             System.out.println("------开始干活啦-------");
38             Thread.sleep(500);
39         }catch(InterruptedException e){
40             e.printStackTrace();
41         }
42         System.out.println("-----工人"+name+"干活结束----");
43         countDownLatch.countDown();
44     }
45 }
46 
47 
48 class Boss implements Runnable{
49     private CountDownLatch countDownLatch;
50     public Boss(CountDownLatch countDownLatch){
51         this.countDownLatch=countDownLatch;
52     }
53 
54     @Override
55     public void run() {
56         System.out.println("老板正在等待所有的工人完工");
57         try {
58             countDownLatch.await();//等待所有和countDown有关的线程执行完毕后才执行本线程
59         } catch (InterruptedException e) {
60             e.printStackTrace();
61         }
62         System.out.println("老板检查工人完工情况结束");
63     }
64 }
View Code

运行结果之一为:(工人工作的先后顺序可能每次运行不一致,但是“老板检查工人完工情况结束”一定是最后完成)

Concurrent同步工具类01 -  CountDownLatch
1 老板正在等待所有的工人完工
2 ------开始干活啦-------
3 ------开始干活啦-------
4 ------开始干活啦-------
5 -----工人w1干活结束----
6 -----工人w3干活结束----
7 -----工人w2干活结束----
8 老板检查工人完工情况结束
View Code

 如果上述countDownLatch的初始化数量由3改为5,将会线程阻塞,其中一种运行情况为:

Concurrent同步工具类01 -  CountDownLatch

 

上一篇:java-如何在调用AsyncTask.cancel()方法时中断AsyncTask中的可调用对象?


下一篇:Java线程池使用的注意事项