Java并发CountDownLatch

CountDownLatch是闭锁的一种应用类,允许一个或多个线程等待某些操作完成,它是采用倒数检查控制线程的执行和等待。

概括的说,定义一个CountDownLatch对象并指定其需要倒数的线程数,通过await方法来阻塞线程,通过countDown方法来将计数器减1,如果计数器减到0,那么await方法的阻塞作用就消失了,当前线程则继续执行。说起来有些绕,一会看demo。

构造器:

CountDownLatch(int count)
Constructs a CountDownLatch initialized with the given count.

方法:

voidawait()Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted.
booleanawait(long timeout, TimeUnit unit)Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted, or the specified waiting time elapses.
voidcountDown()Decrements the count of the latch, releasing all waiting threads if the count reaches zero.
longgetCount()Returns the current count.
StringtoString()Returns a string identifying this latch, as well as its state.

示例代码:

import lombok.SneakyThrows;

import java.util.concurrent.CountDownLatch;

/**
 * CountDownLatch
 */
public class CountDownLatchTest {
    public void timeTasks(int nt,final Runnable task) throws InterruptedException {
        final CountDownLatch startCDL = new CountDownLatch(1);
        final CountDownLatch endCDL = new CountDownLatch(nt);
        for (int i = 0; i < nt; i++) {
            final int j = i;
            Thread t = new Thread(){
                public void run() {
                    try {
                        System.out.println("out i:"+j);
                        startCDL.await();
                        try {
                            System.out.println("inner i:"+j);
                            task.run();
                        }finally {
                            endCDL.countDown();
                        }

                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            t.start();
        }
        Thread.sleep(2000);
        startCDL.countDown();
        endCDL.await();
    }

    public static void main(String[] args) throws InterruptedException {
        CountDownLatchTest t = new CountDownLatchTest();
        t.timeTasks(10, new Task());

    }



}

class Task implements Runnable {

    @SneakyThrows
    @Override
    public void run() {
        //Thread.sleep(200);
        System.out.println("task");
    }
}

输出:

out i:0
out i:1
out i:2
out i:3
out i:5
out i:6
out i:7
out i:4
out i:8
out i:9
inner i:0
inner i:5
inner i:3
inner i:6
inner i:7
task
inner i:8
task
inner i:1
task
inner i:2
task
inner i:9
task
inner i:4
task
task
task
task
task

分析:demo代码创建了两个CountDownLatch,startCDL是控制各线程的开始执行时机,因为startCDL在代码20行对各线程中进行了阻塞,各线程初始化到此则阻塞了,各线程初始化完成后,主线程36行,解除了阻塞,然后各线程每执行完一个,通过endCDL.countDown()方法将计数器减1,直到endCDL的计数器为0,endCDL对主线程的阻塞也解除了。