Java并发之CountDownLatch

Java并发之CountDownLatch

定义

CountDownLatch从意思上看,countdown是倒数的意思,latch的意思是门栓,所以看作是倒数门栓。CountDownLatch的作用也和他的意思一样,主线程可以看作是一个门栓,等到其他线程倒数完成之后,主线程才能继续向下执行。简单来说就是允许一个或者多个线程等待其他线程完成操作。

方法

构造方法,传入需要计数的次数,在count>0之前,线程会一直等待

public CountDownLatch(int count)

调用此方法的线程在计数器为0之前会一直等待,可以由多个线程同时调用此方法,他们都将会等待

public void await() throws InterruptedException

计数器减1,一般是执行任务的方法进行调用

public void countDown()

应用场景

为了对比,这里使用相同的场景,和Java并发之CyclicBarrier的例子一样,但是我们先不使用CountDownLatch来实现这个功能,代码如下:

public class Test {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.println("1号选手 开始准备");
            try {
                Thread.sleep(2000);
                System.out.println("1号选手 准备完成");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread t2 = new Thread(() -> {
            System.out.println("2号选手 开始准备");
            try {
                Thread.sleep(2000);
                System.out.println("2号选手 准备完成");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("选手们准备完成");
    }
}

输出如下

1号选手 开始准备
2号选手 开始准备
1号选手 准备完成
2号选手 准备完成
选手们准备完成

这里使用了Thread类的join()方法来让主线程进行等待,等待t1和t2执行完成后才能继续执行。join()方法会一直检查线程是否存活,如果存活则会一直等待下去。

CountDownLatch实现更加灵活,比join()的功能更多,代码如下:

public class MyThread implements Runnable {
    private String name;
    private CountDownLatch countDownLatch;

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

    @Override
    public void run() {
        try {
            System.out.println(this.name + " 开始准备");
            Thread.sleep(1000 * 3);
            System.out.println(this.name + " 准备完成");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            countDownLatch.countDown();
        }
    }

}
public static void main(String[] args) {
        int corePoolSize = Runtime.getRuntime().availableProcessors() * 2;
        CountDownLatch countDownLatch = new CountDownLatch(corePoolSize);
        ExecutorService executorService = new ThreadPoolExecutor(corePoolSize, corePoolSize, 0L,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>(10));
        for (int i = 1; i <= corePoolSize; i++) &#123;
            executorService.execute(new MyThread(i + "号选手", countDownLatch));
        &#125;
        try &#123;
            countDownLatch.await();
            System.out.println("选手们准备完成");
        &#125; catch (InterruptedException e) &#123;
            e.printStackTrace();
        &#125; finally &#123;
            executorService.shutdown();
        &#125;
&#125;

可以看到在主线程中使用了await()方法,在其他线程执行countdown()方法,在计数器为0之前,主线程会一直等待。在真实开发中,如果某个线程执行时间过长,也可以使用带时间参数的await(long time, TimeUnit unit),这个方法等待指定时间后,就不会再等待了,join()方法也有类似的时间参数

总结

CyclicBarrier不同的是,CountDownLatch不能进行重置,只能使用一次。CyclicBarrier功能也更为丰富,可以参看CyclicBarrier的API。CountDownLatch一般用于某个线程等待若干个其他线程执行完任务之后,它才执行,而CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行。

参考

  • 《Java并发编程的艺术》

   转载规则

本文不允许转载。
 上一篇
如何自己实现一个LRU Cache 如何自己实现一个LRU Cache
如何自己实现一个LRU Cache LRU是Least Recently Used的缩写,即最近最少使用的淘汰,在内存有限的情况下,可以使用这种算法,保持内存中是最热的数据。 思路lru有两种实现方法,可以通过HashMap+双向链表的形
2019-01-21
下一篇 
Java并发之CyclicBarrier Java并发之CyclicBarrier
Java并发之CyclicBarrier定义 CyclicBarrier译为回环栅栏,是J.U.C里面提供的工具,字面意思是可循环使用的屏障,作用是可以让一组线程同时到达某个屏障被阻塞,直到最后一个线程到达屏障之后再全部开始执行,和常见的C
  目录