Java CountDownLatch应用

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

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

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

      举个例子,有三个工人在为老板干活,这个老板有一个习惯,就是当三个工人把一天的活都干完了的时候,他就来检查所有工人所干的活。记住这个条件:三个工人先全部干完活,老板才检查。所以在这里用Java代码设计两个类,Worker代表工人,Boss代表老板,具体的代码实现如下:

//工人类
class Worker implements Runnable {

    private CountDownLatch countDownLatch;
    private String name;

    public Worker(CountDownLatch countDownLatch, String name) {
        this.countDownLatch = countDownLatch;
        this.name = name;
    }

    @Override
    public void run() {
        this.work();
        try {
            TimeUnit.SECONDS.sleep(new Random().nextInt(10));
        } catch (InterruptedException e) {
        } finally {
            this.countDownLatch.countDown(); //闭锁计数器减一
        }
    }

    private void work() {
        System.out.println(this.name + "正在干活。");
    }

}

  

//老板类
class Boss implements Runnable {

    private CountDownLatch countDownLatch;

    public Boss(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        System.out.println("老板正在等待所有公认干完活....");
        try {
            this.countDownLatch.await();
        } catch (InterruptedException e) {
        }
        System.out.println("工人们都干完活了,老板开始检查了!!!!!!!!!!!!!!");
    }
}
/**
 * 闭锁测试
 * Created by gan on 2019/5/18 22:47.
 */
public class CountDownLatchDemo {

    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        CountDownLatch countDownLatch = new CountDownLatch(3);


        Boss b1 = new Boss(countDownLatch);
        Worker w1 = new Worker(countDownLatch, "小王");
        Worker w2 = new Worker(countDownLatch, "校长");
        Worker w3 = new Worker(countDownLatch, "小李");

        executor.execute(b1);
        executor.execute(w1);
        executor.execute(w2);
        executor.execute(w3);

        executor.shutdown();
    }
}

当你运行CountDownLatchDemo这个对象的时候,你会发现是等所有的工人都干完了活,老板才来检查,下面是我本地机器上运行的一次结果,可以肯定的每次运行的结果可能与下面不一样,但老板检查永远是在后面的。

 

同样还可以完成如下功能: "将一个大任务分解为几个小任务用多线程跑,最后统计完成时间" 功能,代码如下:

 1 /**
 2  * Created by gan on 2019/5/19 0:05.
 3  */
 4 public class CountDownLatchDemo2 {
 5 
 6     public static void main(String[] args) throws InterruptedException {
 7         final CountDownLatch countDownLatch = new CountDownLatch(10);
 8         long start = System.currentTimeMillis();
 9 
10         for (int i = 0; i < 10; i++) {
11             int j = i;
12             new Thread(() -> {
13                 try {
14                     TimeUnit.SECONDS.sleep(1);
15                     System.out.println(Thread.currentThread().getName() + "执行完毕....." + j);
16                 } catch (InterruptedException e) {
17                 } finally {
18                     countDownLatch.countDown();
19                 }
20             }).start();
21         }
22 
23         System.out.println("主线程等待子线程完成。。。。");
24         countDownLatch.await(); //主线程到此进入阻塞状态,等待 countDownLatch.countDown()减为0后才进入就绪->执行
25         System.out.println("所有线程执行完毕,一共耗时===================>" + (System.currentTimeMillis() - start));
26 
27     }
28 }

运行结果如下:

参考文章: https://zapldy.iteye.com/blog/746458

原文地址:https://www.cnblogs.com/ganbo/p/10887774.html