CountDownLatch和CyclicBarrier

1. 定义
CountDownLatch提供了一个栅栏,在这个栅栏这里有n个线程等待另外m个线程完成任务的一个组件。
CyclicBarrier提供了一个屏障,保证n个线程全部到达这个屏障之后,再继续执行后续的代码。

2. 对比

  1. 二者语义有所不同,CountDownLatch提供的n个线程等待m个线程的组件,而CyclicBarrier提供的是一个对n个线程进行步调调整的组件。
  2. CountDownLatch使用更加简单,灵活,可以在一个线程中多次countDown,CyclicBarrier不支持。
  3. CountDownLatch的计数器不支持重置,CyclicBarrier支持。
  4. CyclicBarrier提供barrierAction,在线程全部到达后,立即执行这一任务,CountDownLatch不支持

3. 应用场景
CountDownLatch常用于主线程等待多个子线程执行任务完成,然后进行下一步操作。
CyclicBarrier可以提供一种简易的,轻量的类MapReduce操作,可以手动分配(map)任务给线程池,然后用barrierAction(reduce)来处理多个线程的执行结果。

4. Demo
CountDownLatch:

package org.lyh;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class CountDownLatchDemo {

    private static CountDownLatch c = new CountDownLatch(3);

    public static void main(String[] args) throws InterruptedException {
        ExecutorService es = Executors.newFixedThreadPool(2);
        /**
         * countDown可以在任何地方调用,比如在一个线程中调用两次,保证自己的逻辑是正确的即可
         */
        es.execute(new Thread(()->{
            System.out.println(1);
            c.countDown();
            try {
                TimeUnit.MILLISECONDS.sleep(2000); //do something
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(2);
            c.countDown();
        }));
        es.execute(new Thread(()->{
            System.out.println(3);
            c.countDown();
        }));

        /**
         * 主线程和一个子线程都在等在CountDownLatch计数达到0
         */
        es.execute(new Thread(()->{
            try {
                c.await();
                System.out.println("子线程等待结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }));
        c.await(1000, TimeUnit.MILLISECONDS);//设置最长等待时间
        es.shutdown();
        System.out.println("主线程等待结束");
    }
}

CyclicBarrier:

package org.lyh;

import java.util.concurrent.*;

public class CyclicBarrierDemo implements Runnable{

    /**
     * CyclicBarrier设置最多等待的任务数量,以及全部任务结束以后立即执行的任务(非必选)
     */
    private static CyclicBarrier c = new CyclicBarrier(3, new CyclicBarrierDemo());

    public static void main(String[] args) {
        ExecutorService es = Executors.newFixedThreadPool(2);
        /**
         * await在一个线程里只能调用一次,不能多次调用,CyclicBarrier也不存在多个线程专门等待n个线程的问题
         * 而是让这n个线程全部阻塞在await调用的地方,仔细想想和CountDownLatch还是有许多不同
         * 而且CyclicBarrier支持重置计数器,可以支持更加复杂的业务场景
         */
        es.execute(new Thread(()->{
            try {
                c.await();
                TimeUnit.MILLISECONDS.sleep(2000); //do something
                System.out.println(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }));
        es.execute(new Thread(()->{
            System.out.println(3);
            try {
                c.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }));
        try {
            System.out.println(2);
            c.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
        es.shutdown();
        System.out.println("所有线程全部结束");
    }

    @Override
    public void run() {
        System.out.println("这是结束的工作");
    }
}

CountDownLatch和CyclicBarrier分别是基于AQS和ReentrantLock实现的,具体原理需要的时候可以看源码。

参考文献:
《Java编程思想》
《Java并发编程的艺术》

你可能感兴趣的:(Java并发)