学用 CountDownLatch 与 CyclicBarrier

开篇即说结论,如果搞不清楚两者区别,那就无脑用 CountDownLatch,问题也不大(因为我也不是太懂)。

CountDownLatch

模拟了100米赛跑,10名选手已经准备就绪,只等裁判一声令下。当所有人都到达终点时,比赛结束。

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

/**
 * 模拟了100米赛跑,10名选手已经准备就绪,只等裁判一声令下。当所有人都到达终点时,比赛结束。
 * ...
 *
 * @author liuchao
 */
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        //10名运动员
        final CountDownLatch count = new CountDownLatch(10);

        //java的线程池
        final ExecutorService executorService = Executors.newFixedThreadPool(5);

        for (int index = 1; index <= 10; index++) {
            final int number = index;

            executorService.submit(() -> {
                try {
                    Thread.sleep((long) (Math.random() * 10000));
                    System.out.println(number + ": arrived");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    count.countDown();// 运动员到达终点,count数减一
                }
            });
        }


        System.out.println("Game Started");
        //等待count数变为0,否则会一直处于等待状态,游戏就没法结束了
        count.await();
        System.out.println("Game Over");
        //关掉线程池
        executorService.shutdown();
    }
}

运行结果:

学用 CountDownLatch 与 CyclicBarrier_第1张图片

CyclicBarrier

继续还是这10个人,这次没裁判。规定10个人只要都跑到终点了,大家可以喝啤酒。但是,只要有一个人没到终点,就不能喝。 这里也没有要求大家要同时起跑(当然也可以,加 latch)

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        final int count = 5;
        final CyclicBarrier barrier = new CyclicBarrier(count, () -> System.out.println("drink beer!"));

        // they do not have to start at the same time...
        for (int i = 0; i < count; i++)
            new Thread(new Worker(i, barrier)).start();
    }
}

class Worker implements Runnable {
    final int id;
    final CyclicBarrier barrier;

    public Worker(final int id, final CyclicBarrier barrier) {
        this.id = id;
        this.barrier = barrier;
    }

    @Override
    public void run() {
        try {
            System.out.println(id + "starts to run !");
            Thread.sleep((long) (Math.random() * 10000));
            System.out.println(id + "arrived !");
            barrier.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

运行结果:
学用 CountDownLatch 与 CyclicBarrier_第2张图片

总结

  • CountDownLatch 强调一个线程等多个线程完成某件事情。CyclicBarrier 是多个线程互等,等大家都完成。
  • CountDownLatch 很明显是可以不限制等待线程的数量,而会限制 countDown的操作数;CyclicBarrier 会限制等待线程的数量
  • 写法当然不一样,看看下面的伪代码
class CountDownLatch{
    CountDownLatch cd = new CountDownLatch(5);
    main(){
        启动5个线程。。。
        cd.await(); //让当前线程休眠,
        执行代码... (该代码不会立即执行,等待5个线程执行完成后,当前线程会被唤醒,继续执行后面的代码)
    }

    class Th extends Thread{
        public void run() {
            执行代码...
            cd.countDown(); //报告CountDownLatch 当前线程已经到位
            执行代码...(该代码不会因为countDown()而阻塞,countDown()没有阻塞效果)    

        }
    }

}

// 没有指定 构造线程的barrier伪代码
class CyclicBarrier{
    CyclicBarrier cd = new CyclicBarrier(5);
    main(){
        启动5个线程。。。
        执行代码...; //该代码会被立即执行
    }

    class Th extends Thread{
        public void run() {
            执行代码...
            cb.await(); //barrier参与量+1,并且当前线程休眠
            执行代码...(该代码不会立即执行,只有等待指定的5个线程集合了后,该代码才会继续执行)    
        }
    }

}

// 指定 构造线程的barrier伪代码
class CyclicBarrier{
    CyclicBarrier cd = new CyclicBarrier(5,runable);
    main(){
        启动5个线程。。。
        执行代码...; //该代码会被立即执行
    }

    class Th extends Thread{
        public void run() {
            执行代码...
            cb.await(); //barrier参与量+1,并且当前线程休眠
            执行代码...(该代码不会立即执行,只有等待指定的5个线程集合了后,会启动构造传入的runable线程代码,该线程结束后(所有等待的线程才能被唤醒),该代码才会继续执行)   
        }
    }

}

参见

  • CountDownLatch与CyclicBarrier 通熟易懂
  • CyclicBarrier正确的使用方法和错误的使用方法
  • Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
  • 多线程并发之CyclicBarrier(栅栏)使用详解
  • 关于CyclicBarrier与CountDownLatch的源码比较-CountDownLatch 使用场景
  • [Java7并发编程实战手册]3.5 在集合点的同步CyclicBarrier循环barrier
  • Java CyclicBarrier vs CountDownLatch

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