CountDownLatch和Cyclibarrier

CountDownLatch和Cyclibarrier 都是jdk并发包中提供的用于多个线程都达到某个点后再进行操作的工具类

CountDownLatch

countDownLatch 是一个倒计时器,它可以让某一个线程等待直到得到及时结束才开始执行。

  1. 构造函数可接收一个整数作为参数,表示计数器的计数个数
public CountDownLatch(int count)
  1. demo
public class CountDownLatchTest {

    public static class Soldier implements Runnable {

        CountDownLatch latch;
        int i;
        public Soldier(CountDownLatch latch,  int i) {
           this.latch = latch;
           this.i = i;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(Math.abs(new Random().nextInt() % 10000));
                System.out.println("士兵" + (i + 1) + "在任务完成");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                latch.countDown();
            }
        }
    }

    public static class General implements Runnable{

        CountDownLatch latch;

        public General (CountDownLatch latch) {
           this.latch = latch;
        }

        @Override
        public void run() {
            try {
                latch.await(10, TimeUnit.SECONDS);
                System.out.println("司令:任务完成");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        ExecutorService executor = new ThreadPoolExecutor(0, 10,
                0L, TimeUnit.SECONDS, new SynchronousQueue(),new ThreadPoolExecutor.CallerRunsPolicy());

        int n = 10;
        CountDownLatch latch = new CountDownLatch(n);

        for (int i = 0; i < 10; i++) {
            executor.submit(new Soldier(latch, i));
        }
        executor.submit(new General(latch));
    }
}
 
输出结果
士兵1在任务完成
士兵7在任务完成
士兵4在任务完成
士兵2在任务完成
士兵8在任务完成
士兵6在任务完成
士兵10在任务完成
士兵3在任务完成
士兵9在任务完成
士兵5在任务完成
司令:任务完成

每一个士兵线程在线程执行完毕后调用了countDownLatch.countDown(),倒计时会减1,司令线程在执行到countDownLatch.await()时,如果countDownLatch不是0则等待到一直到倒计时为0后才继续执行!

CycliBarrier

CycliBarrier与countDownLatch有类似的功能且比CountDownLatch更强大。CycliBarrier好比如栅栏,当线程都执行到某一点后,将线程拦了下来,所有线程都达到后再继续下面操作。且CycliBarrir可以循环利用。

  1. 构造方法,第一个参数表示参与的线程总数,第二个参数表示后续操作
public CyclicBarrier(int parties, Runnable barrierAction)
  1. demo
public class CycliBarrierTest {

    public static class Soldier implements Runnable {
        private String soldier;
        private final CyclicBarrier cyclic;

        public Soldier(CyclicBarrier cyclic, String soldier) {
            this.soldier = soldier;
            this.cyclic = cyclic;
        }

        @Override
        public void run() {
            try {
                cyclic.await();
                doWork();
                cyclic.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }

        void doWork() {
            try {
                Thread.sleep(Math.abs(new Random().nextInt() % 10000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(soldier + ":任务完成");
        }

    }

    public static class BarrierRun implements Runnable {
        boolean flag;
        int N;

        public BarrierRun(boolean flag, int N) {
            this.flag = flag;
            this.N = N;
        }

        @Override
        public void run() {
            if (flag) {
                System.out.println("司令:[士兵" + N + "个,任务完成!]");
            } else {
                System.out.println("司令:[士兵" + N + "个,集合完毕!]");
                flag = true;
            }
        }
    }

    public static void main(String[] args) {
        final int N = 10;
        Thread[] allSoldier = new Thread[N];
        boolean flag = false;
        CyclicBarrier cyclic = new CyclicBarrier(N, new BarrierRun(flag, N));
        //设置屏障点,主要为了执行这个方法
        System.out.println("集合队伍! ");
        for (int i = 0; i < N; i++) {
            System.out.println("士兵" + i + "报道! ");
            allSoldier[i] = new Thread(new Soldier(cyclic, "士兵" + i));
            allSoldier[i].start();
        }
    }
}

执行结果

集合队伍! 
士兵0报道! 
士兵1报道! 
士兵2报道! 
士兵3报道! 
士兵4报道! 
士兵5报道! 
士兵6报道! 
士兵7报道! 
士兵8报道! 
士兵9报道! 
司令:[士兵10个,集合完毕!]
士兵1:任务完成
士兵7:任务完成
士兵5:任务完成
士兵3:任务完成
士兵6:任务完成
士兵9:任务完成
士兵2:任务完成
士兵8:任务完成
士兵0:任务完成
士兵4:任务完成
司令:[士兵10个,任务完成!]

士兵线程的run方法中,在执行前调用了cycliBarrir的await(),等待所有线程都到达后,当所有线程都到达后,这一次的计数完成,当work()后再一次调用了await()方法,重新进行下一次计数

区别

CountDownLatch是在当所有线程都到达某一点后,等待的线程才可以继续进行。CycliBarrir 是在线程都到达某一点后,先到达的线程会等待到所有线程都到达后再继续进行!

你可能感兴趣的:(java)