barrier(CyclicBarrier和CountDownLatch的用法与区别)

更新时间:2024-05-12 03:59:47 所在栏目: 美容养生点击量:

CyclicBarrier和CountDownLatch的用法与区别

原文链接:
blog.csdn.net/zyzzxycj/article/details/90241892

弁言

CyclicBarrier和CountDownLatch这两个东西都是在java.util.concurrent包下,并且平常很多场景都市使用到。

本文将会对两者举行分析,纪录他们的用法和区别。

CountDownLatch

CountDownLatch是一个十分实用的多线程控制东西类,称之为“倒计时器”,它允许一个或多个线程不休等候,直到其他线程的利用实行完后再实行。

CountDownLatch是经过一个计数器来完成的,计数器的初始值为线程的数目。每当一个线程完成了本人的职责后,计数器的值就会减1。当计数器值抵达0时,它表现一切的线程以前完成了职责,然后在闭锁上等候的线程就可以规复实行职责。

特点

只能一次性使用(不克不及reset);主线程壅闭;某个线程中缀将永久到不了屏蔽点,一切线程都市不休等候。

例子

//创建初始化3个线程的线程池 private ExecutorService threadPool = Executors.newFixedThreadPool(3); //保存每个学生的均匀成果 private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); private CountDownLatch countDownLatch = new CountDownLatch(3); private void count() { for (int i = 0; i < 3; i++) { threadPool.execute(() -> { //盘算每个学生的均匀成果,代码略()假定为60~100的随机数 int score = (int) (Math.random() * 40 + 60); try { Thread.sleep(Math.round(Math.random() * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } map.put(Thread.currentThread().getName(), score); System.out.println(Thread.currentThread().getName() + "同砚的均匀成果为" + score); countDownLatch.countDown(); }); } this.run(); threadPool.shutdown(); } @Override public void run() { try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } int result = 0; Set<String> set = map.keySet(); for (String s : set) { result += map.get(s); } System.out.println("三人均匀成果为:" + (result / 3) + "分"); } public static void main(String[] args) throws InterruptedException { long now = System.currentTimeMillis(); CyclicBarrier1 cb = new CyclicBarrier1(); cb.count(); Thread.sleep(100); long end = System.currentTimeMillis(); System.out.println(end - now); }

终极输入后果:

此中1194ms证实白会壅闭主线程。

CyclicBarrier

CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏蔽(Barrier)。它要做的事变是,让一组线程抵达一个屏蔽(也可以叫同步点)时被壅闭,直到最初一个线程抵达屏蔽时,屏蔽才会开门,一切被屏蔽拦阻的线程才会持续干活。

这个屏蔽之以是用循环修饰,是由于在一切的线程开释互相之后,这个屏蔽是可以重新使用的(reset()办法重置屏蔽点),这一点与CountDownLatch不同。

CyclicBarrier是一种同步机制允许一组线程互相称待,比及一切线程都抵达一个屏蔽点才退去await办法,它没有直接完成AQS而是借助ReentrantLock来完成的同步机制。

它是可循环使用的,而CountDownLatch是一次性的,别的它体现的语义也跟CountDownLatch不同,CountDownLatch变小计数抵达条件接纳的是release办法,而CyclicBarrier走向屏蔽点(await)接纳的是Acquire办法,Acquire是会壅闭的,这也完成了CyclicBarrier的别的一个特点,只需有一个线程中缀那么屏蔽点就被冲破,一切线程都将被叫醒(CyclicBarrier本人卖力这局部完成,不是由AQS调治的),如此也制止了由于一个线程中缀惹起永久不克不及抵达屏蔽点而招致其他线程不休等候。

屏蔽点被冲破的CyclicBarrier将不成再使用(会抛出BrokenBarrierException)除非实行reset利用。

布局函数

CyclicBarrier有两个布局函数:

  • CyclicBarrier(int parties)int典范的参数表现有几个线程分开场这个屏蔽拦阻,(拿外表的例子,即有几一局部跟团旅游);
  • CyclicBarrier(int parties,Runnable barrierAction)当一切线程抵达一个屏蔽点时,优先实行barrierAction这个线程。

最紧张的是一个办法:

  • await():每个线程调用await(),表现我以前抵达屏蔽点,然后当前线程被壅闭。

例子

//创建初始化3个线程的线程池 private ExecutorService threadPool = Executors.newFixedThreadPool(3); //创建3个CyclicBarrier目标,实行完后实行如今类的run办法 private CyclicBarrier cb = new CyclicBarrier(3, this); //保存每个学生的均匀成果 private ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>(); private void count() { for (int i = 0; i < 3; i++) { threadPool.execute(() -> { //盘算每个学生的均匀成果,代码略()假定为60~100的随机数 int score = (int) (Math.random() * 40 + 60); try { Thread.sleep(Math.round(Math.random() * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } map.put(Thread.currentThread().getName(), score); System.out.println(Thread.currentThread().getName() + "同砚的均匀成果为" + score); try { //实行完运转await(),等候一切学生均匀成果都盘算终了 cb.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } }); } threadPool.shutdown(); } @Override public void run() { int result = 0; Set<String> set = map.keySet(); for (String s : set) { result += map.get(s); } System.out.println("三人均匀成果为:" + (result / 3) + "分"); } public static void main(String[] args) throws InterruptedException { long now = System.currentTimeMillis(); CyclicBarrier1 cb = new CyclicBarrier1(); cb.count(); Thread.sleep(100); long end = System.currentTimeMillis(); System.out.println(end - now); }

终极输入后果:

显然没有壅闭主线程。

两者区别

  • CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset()办法重置。以是CyclicBarrier能处理更为繁复的业务场景,好比假如盘算产生错误,可以重置计数器,并让线程们重新实行一次。
  • CyclicBarrier还提供其他有效的办法,好比getNumberWaiting办法可以取得CyclicBarrier壅闭的线程数目。isBroken办法用来晓得壅闭的线程对否被中缀。好比以下代码实行完之后会前往true。
  • CountDownLatch会壅闭主线程,CyclicBarrier不会壅闭主线程,只会壅闭子线程。
  • 某线程中缀CyclicBarrier会抛出特别,制止了一切线程无穷等候。

我们来从jdk作者计划的目标来看,javadoc是这么形貌它们的:

CountDownLatch: A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

CyclicBarrier: A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point.

从javadoc的形貌可以得出:

  • CountDownLatch:一个大概多个线程,等候其他多个线程完成某件事变之后才干实行;
  • CyclicBarrier:多个线程互相称待,直到抵达同一个同步点,再持续一同实行。

关于CountDownLatch来说,重点是“一个线程(多个线程)等候”,而其他的N个线程在完成“某件事变”之后,可以停止,也可以等候。

而关于CyclicBarrier,重点是多个线程,在随意一个线程没有完成,一切的线程都必需等候。

CountDownLatch是计数器,线程完成一个纪录一个,只不外计数不是递增而是渐减,而CyclicBarrier更像是一个阀门,必要一切线程都抵达,阀门才干掀开,然后持续实行。

声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。