背景
在java.util.concurrent包中,有一个CountDownLatch的多线程同步器。含义参考javadoc的说明如下:
“A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.”
即它是当前线程用于等待若干子线程结束或超时的通知,用于自身继续处理的同步工具。一个典型使用场景是同步转异步处理:主线程的任务,进行拆分后,由子线程异步处理;处理结束后,主线程进行结果合成返回。
关键方法
a) 构造方法:CountDownLatch的构造函数只有一个
public CountDownLatch(int count);
入参为子线程组中子线程的数量。
b) countDown方法:
public void countDown();
当前线程任务已经就绪时调用,触发倒数计数,表示任务已经完成。
c)await方法:
//等待其它线程倒数结束才返回,否则一直阻塞
public void await() throws InterruptedException; //等待其它线程倒数结束,或超过指定的时间 public boolean await(long timeout, TimeUnit unit) throws InterruptedException;
当前线程等待其它子线程任务结束,如果当前计数为0,则直接返回,否则表明所关联的其它线程任务并没有结束,当前线程将阻塞,直到计数器归0或超时。
一个示例
一个火箭发射任务的示例源代码如下。假定,main方法是用于火箭发射的整体任务,任务发射需要另外两个人进行相应倒数任务的处理,一个人仅负责偶数序号任务处理,另外一个人仅负责奇数序号任务的处理。
import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicInteger; public class RocketFire { private static final CountDownLatch beginSignal = new CountDownLatch(1); private static final CountDownLatch endSignal = new CountDownLatch(2); private static final AtomicInteger counter = new AtomicInteger(10); public static void main(String[] args) throws InterruptedException { System.out.println("开始倒数"); ExecutorService fixedThreadPool = Executors.newFixedThreadPool(2); fixedThreadPool.submit(new NumberPrinter(true, beginSignal, endSignal)); fixedThreadPool.submit(new NumberPrinter(false, beginSignal, endSignal)); beginSignal.countDown(); endSignal.await(); System.out.println("点火!!"); fixedThreadPool.shutdown(); } private static class NumberPrinter implements Runnable { private final boolean evenNumberPrinter; private final CountDownLatch begin; private final CountDownLatch end; public NumberPrinter(boolean evenNumberPrinter, CountDownLatch begin, CountDownLatch end) { this.evenNumberPrinter = evenNumberPrinter; this.begin = begin; this.end = end; } @Override public void run() { try { begin.await(); } catch (InterruptedException e) { e.printStackTrace(); } while (true) { synchronized (counter) { int v = counter.get(); if (v < 1) { break; } if ((evenNumberPrinter && v % 2 == 0) || (!evenNumberPrinter && v % 2 == 1)) { System.out.println(counter.getAndDecrement()); } } } end.countDown(); } } }
输出如下:
开始倒数 10 9 8 7 6 5 4 3 2 1 点火!!