倒计时门栓CountDownLatch(gold_axe)

大概含义是指,它相当于是一个门栓,一开始是关闭的,所有希望通过该门的线程都需要等待,然后开始倒计时,倒计时变为0后,门栓打开,等待的所有线程都可以通过,它是一次性的,打开后就不能再关上了。

主要用于

不同角色线程间的同步,比如在"裁判"-"运动员"模式中,"裁判"线程让多个"运动员"线程同时开始,也可以用于协调主从线程,让主线程等待多个从线程的结果。


https://mp.weixin.qq.com/s/8F2fQVvS9EVU1Fa-J21oYg

CountDownLatch里有一个计数,这个计数通过构造方法进行传递:

public CountDownLatch(int count)

多个线程可以基于这个计数进行协作,它的主要方法有:

public void await() throws InterruptedException
public boolean await(long timeout, TimeUnit unit) throws InterruptedException
public void countDown() 

countDown() 之前的操作, await往下保证可见

一个简易版的

public class MyLatch {

    private int count;
    //初始化就指定count
    public MyLatch(int count) {
        this.count = count;
    }

    public synchronized void await() throws InterruptedException {
        while (count > 0) {
            wait();//等这
        }
    }

    //count往下减1,每次都检查下是不是可以唤醒了
    public synchronized void countDown() {
     
        if (count == 0) {
            notifyAll();
        }
       if (count > 0) {
            count--;
        }
      
    }
}

注意: 计数到0以后, 再来就一律不停了

使用的例子1,全部结束后开始

public class MasterWorkerDemo {

    static class Worker extends Thread {
// CountDownLatch 一样
        MyLatch latch;

        public Worker(MyLatch latch) {
            this.latch = latch;
        }

        @Override
        public void run() {
            try {
                // simulate working on task
                Thread.sleep((int) (Math.random() * 1000));
            } catch (Exception e) {
            }finally{
                            //latch里面计数-1 ,如果到0了就notifyAll
                this.latch.countDown();
                        }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        int workerNum = 100;
// CountDownLatch 一样
        MyLatch latch = new MyLatch(workerNum);
        Worker[] workers = new Worker[workerNum];
        for (int i = 0; i < workerNum; i++) {
            workers[i] = new Worker(latch);
            workers[i].start();//开始计时
        }
                // countDownLatch.await(10, TimeUnit.MILLISECONDS);//指定最长等待时间
        latch.await();//内部计数没到0就wait

        System.out.println("collect worker results");
    }

}

注意:

  • 不论成败都要往下执行, 所以latch.countDown();要放finally{这里面}
  • 如果不这么做 就弄个时机限制 保证能往下走

例子2,一起开始

public class RacerWithLatchDemo {
    static class Racer extends Thread {
// CountDownLatch 一样
        MyLatch latch;

        public Racer(MyLatch latch) {
            this.latch = latch;
        }

        @Override
        public void run() {
            try {
                //全部先等着
                this.latch.await();
                System.out.println("start run "
                        + Thread.currentThread().getName());
            } catch (InterruptedException e) {
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        int num = 10;
        
        //这里计数只有1
        MyLatch latch = new MyLatch(1);
//一样的
//CountDownLatch latch = new CountDownLatch(1);
        
        Thread[] racers = new Thread[num];
        for (int i = 0; i < num; i++) {
            racers[i] = new Racer(latch);
            racers[i].start();
        }
        Thread.sleep(1000);
        
        //一起开始
        latch.countDown();
    }

}

例子3,设时限

public class CountDownLatchExample2 {

    private final static int threadCount = 200;

    public static void main(String[] args) throws Exception {

        ExecutorService exec = Executors.newCachedThreadPool();

        final CountDownLatch countDownLatch = new CountDownLatch(threadCount);

        for (int i = 0; i < threadCount; i++) {
            final int threadNum = i;
            exec.execute(() -> {
                try {
                    test(threadNum);
                } catch (Exception e) {
                    log.error("exception", e);
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        countDownLatch.await(10, TimeUnit.MILLISECONDS);//最多等10秒就往下执行了,当然 也不会阻止那些线程运行完
        log.info("finish");
        exec.shutdown();//所有执行完后关闭
    }

    private static void test(int threadNum) throws Exception {
        Thread.sleep(100);
        log.info("{}", threadNum);
    }
}

你可能感兴趣的:(倒计时门栓CountDownLatch(gold_axe))