• 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
    点火!!
  • 相关阅读:
    Qt中实现单例模式(SingleTon)
    毕设开发手记(二)
    Qt中由表中单元格的QModelIndex获取Global Pos的正确方法
    Qt的槽可以使用默认参数
    C#结构的了解
    dos命令集江南技术联盟
    C#中的abstract与virtual的用法
    [转]六种删除数据库重复行的方法
    PL/SQL的TO_CHAR()与TO_DATE()
    索引索引索引(转)
  • 原文地址:https://www.cnblogs.com/jacksonshi/p/14398540.html
Copyright © 2020-2023  润新知