看到这两个JUC工具类,再也不会一脸茫然了!!!

CountDownLatch和cyclicBarrier都是Java.util.concurrent包下面的多线程工具类。

字面理解

  • countDown表示减法计数,Latch表示门闩,当计数为0,就打开门闩
  • cyclicBarrier表示循环的障碍物。

两个类都含有这个意思:对应的线程完成工作之后再进行下一步动作,也就是大家都准备好之后再进行下一步。然而两者最大的区别是,进行下一步动作的动作实施着不同。

countDownLatch的动作实施者是“当前线程”,cyclicBarrier是其他线程。

举例说明:

对于CountDwonLatch,用王者荣耀游戏为例,其他线程为游戏玩家,当前线程为控制游戏开始的线程。当前线程处于等待状态,意味着游戏不能开始。当所有的玩家都准备好之后,游戏才能开始。

  • `正在等待所有玩家准备好
  • player0 已经准备好了, 所使用的时间为 1.235s
  • player2 已经准备好了, 所使用的时间为 1.279s
  • player3 已经准备好了, 所使用的时间为 1.358s
  • player1 已经准备好了, 所使用的时间为 2.583s
  • 开始游戏`

CountDownLatch的代码:

import java.util.Random;
import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(4);
        for(int i = 0; i < latch.getCount(); i++){
            new Thread(new MyThread(latch), "player"+i).start();
        }
        System.out.println("正在等待所有玩家准备好");
        latch.await();
        System.out.println("开始游戏");
    }

    private static class MyThread implements Runnable{
        private CountDownLatch latch ;

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

        @Override
        public void run() {
            try {
                Random rand = new Random();
                int randomNum = rand.nextInt((3000 - 1000) + 1) + 1000;//产生1000到3000之间的随机整数
                Thread.sleep(randomNum);
                System.out.println(Thread.currentThread().getName()+" 已经准备好了, 所使用的时间为 "+((double)randomNum/1000)+"s");
                latch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}
复制代码

对于CyclicBarrier,用公司活动举例,假设有一家公司要全体员工进行团建活动,活动内容为翻越三个障碍物,每一个人翻越障碍物所用的时间不一样,但是游戏规则要求所有人要都翻越完当前的障碍物后才可以翻越下一个障碍物。类比地,每一个参与活动的玩家都是“其他线程”,当所有人都翻越了所有障碍物之后,程序才结束。此时“当前线程可能已经结束”,cyclicBarrier不管先当前线程的执行状态。

我们使用代码来模拟上面的过程。我们设置了三个员工和三个障碍物。可以看到所有的员工翻越了第一个障碍物之后才开始翻越第二个的,下面是运行结果:

  • main function is finished.
  • 队友1, 通过了第0个障碍物, 使用了 1.432s
  • 队友0, 通过了第0个障碍物, 使用了 1.465s
  • 队友2, 通过了第0个障碍物, 使用了 2.26s
  • 队友1, 通过了第1个障碍物, 使用了 1.542s
  • 队友0, 通过了第1个障碍物, 使用了 2.154s
  • 队友2, 通过了第1个障碍物, 使用了 2.556s
  • 队友1, 通过了第2个障碍物, 使用了 1.426s
  • 队友2, 通过了第2个障碍物, 使用了 2.603s
  • 队友0, 通过了第2个障碍物, 使用了 2.784s

代码:

package com.huai.thread;

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

public class CyclicBarrierTest {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(3);
        for(int i = 0; i < barrier.getParties(); i++){
            new Thread(new MyRunnable(barrier), "队友"+i).start();
        }
        System.out.println("main function is finished.");
    }


    private static class MyRunnable implements Runnable{
        private CyclicBarrier barrier;

        public MyRunnable(CyclicBarrier barrier){
            this.barrier = barrier;
        }

        @Override
        public void run() {
            for(int i = 0; i < 3; i++) {
                try {
                    Random rand = new Random();
                    int randomNum = rand.nextInt((3000 - 1000) + 1) + 1000;//产生1000到3000之间的随机整数
                    Thread.sleep(randomNum);
                    System.out.println(Thread.currentThread().getName() + ", 通过了第"+i+"个障碍物, 使用了 "+((double)randomNum/1000)+"s");
                    this.barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
复制代码

总结:CountDownLatch和cyclicBarrier都有让多个线程等待同步然后再开始下一步动作的意思,但是countDwonLatch的下一步动作实施者是当前线程,具有不可重复性。而cyclicBarrier的下一步动作实施者是“其他线程”本身,具有往复多次实施动作的特点。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享