并发编程系列之CyclicBarrier用法简介

x33g5p2x  于2021-12-30 转载在 其他  
字(2.2k)|赞(0)|评价(0)|浏览(407)

1、CyclicBarrier循环屏障定义

定义:协同指定数目的线程,让这些线程都在这个屏障前等待,直到所有的线程都到这个屏障前,再一起继续执行。线程执行完成后,这个屏障可以再次使用,因此被称之为循环屏障。

2、CyclicBarrier用法以及原理

  • 构造方法,CyclicBarrier(int parties):parties指定有多少个部分(线程)参与,称之为参与数。

  • 构造方法,CyclicBarrier(int parties,Runnable barrierAction):barrierAction,所有参与者都到达屏障时执行一次的命令。在一组线程中最后一个线程到达之后(但在释放所有线程之前),在该线程中执行改命令,该命令只在每个屏障点运行一次。若要在继续执行所有线程之前更新共享状态,此屏障操作很有用。

  • int await() throws InterruptedException,BrowkenBarrierException:线程执行过程会调用await()方法,表明自己已经到达屏障,该线程自己阻塞,等待其它线程也到达屏障;当所有线程都到达屏障,也即线程等待数等于参与数,则释放所有线程,让它们继续执行。返回值int表示到达当前线程的索引号,注意索引号是从parties-1开始减为0。BrokenBarrierException,屏障被破坏异常,当调用await时,或等待过程中屏障被破坏,则会抛出BrokenBarrierException

  • int await(long timeout,TimeUnit unit) throws InterruptedException,BrokenBarrierException,TimeoutException:等待指定时长,如到了时间还不能释放,则将抛出TimeoutException

  • int getNumberWaiting(): 获取当前在屏障处的线程数

  • boolean isBroken(): 判断屏障是否被破坏

  • void reset():重置屏障为初始化状态。如果当前有线程正在等待,则这些线程将被释放并抛出BrokenBarrierException

3、CyclicBarrier使用注意事项

  • 一定要确保有足够多的参与者线程,否则会一直阻塞在屏障处。
  • 在线程池中使用要注意,确保线程池的线程数大于等于参与数。

4、CyclicBarrier适用场景

  • 线程等待一起执行
  • 多次等待一起执行

5、CountDownLatch和CyclicBarrier对比

  • CountDownLatch是一部分线程等待另外一部分线程来唤醒
  • CyclicBarrier是参与线程彼此等待,都到达了,再一起执行
  • CountDownLatch不可以循环引用,CyclicBarrier可以循环使用

6、CyclicBarrier例子

  • 场景:多阶段等待一起出发
    案例:公司组织周末旅游活动,大家各自从家出发到公司集合,大家都到了之后,出发到公司各自游玩,然后在公园门口集合,再去餐厅就餐,大家都到了就开始用餐。使用并非编程模拟场景。

参与者不变,多次彼此等待。正好可用CyclicBarrier的循环使用特性

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

public class CyclicBarrierExample {

    public static void main(String[] args) {
        int concurrency = 100;
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(concurrency , ()->{
            System.out.println("*****************准备完成!************");
        });
        final Random random = new Random();
        for (int i = 0 ; i < concurrency; i++) {
            new Thread(() -> {
                try {
                    Thread.sleep(random.nextInt(10_000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "准备就绪");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(
                        Thread.currentThread().getName() + " 开始工作....");
            }).start();
        }
    }
}

控制台打印:

... 
Thread-12准备就绪
Thread-58准备就绪
Thread-75准备就绪
Thread-25准备就绪
*****************准备完成!************
Thread-25 开始工作....
Thread-89 开始工作....
Thread-34 开始工作....
...

相关文章