Java多线程之CountDownLatch

背景

在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
点火!!

 

posted on 2021-02-12 10:13  浪荡绅士  阅读(105)  评论(0编辑  收藏  举报

导航