Java 并发编程(十三):并发工具 CyclicBarrier

版权声明:本文为博主原创文章,转载请注明出处 https://blog.csdn.net/u010647035/article/details/86662077

CyclicBarrier(内存同步屏障)

1、简介

CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(intparties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞

2、类图

在这里插入图片描述

await() : 等待当前 CyclicBarrier 对象上的其它线程调用 await()。

  • 如果当前调用是最后一个调用,则唤醒所有其它的线程;

  • 如果在构造CyclicBarrier时指定了action,当前线程会去执行该action,然后该方法返回该线程调用await的次序(getParties()-1说明该线程是第一个调用await的,0说明该线程是最后一个执行await的),接着该线程继续执行await后的代码;

  • 如果该调用不是最后一个调用,则阻塞等待;

  • 如果等待过程中,当前线程被中断,则抛出InterruptedException;如果等待过程中,其它等待的线程被中断,或者其它线程等待超时,或者该barrier被reset,或者当前线程在执行barrier构造时注册的action时因为抛出异常而失败,则抛出BrokenBarrierException。

await(long timeout, TimeUnit unit):
与await() 的不同点在于设置了等待超时时间,等待超过指定时间会抛出TimeoutException

reset() : 该方法会将该barrier重置为它的初始状态,并使得所有对该barrier的await调用抛出BrokenBarrierException。

3、代码示例

package com.lkf.concurrent;

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

public class CyclicBarrierTest {
    public static void main(String[] args) {
        //初始化四个线程
        int threadNum = 4;
        CyclicBarrier barrier = new CyclicBarrier(threadNum, new WorkerThreadA());
        for (int i = 0; i < threadNum; i++) {
            new WorkerThread(barrier).start();
        }
    }

    static class WorkerThread extends Thread {
        private CyclicBarrier cyclicBarrier;

        public WorkerThread(CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }

        @Override
        public void run() {
            System.out.println("线程" + Thread.currentThread().getName() + "正在执行");
            try {
                Thread.sleep(5000);      //以睡眠来模拟操作
                System.out.println("线程" + Thread.currentThread().getName() + "执行完毕,等待其他线程执行完成");
                cyclicBarrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println("所有线程执行完成,继续处理其他任务...");
        }
    }

    static class WorkerThreadA extends Thread {
        @Override
        public void run() {
            System.err.println("我是特殊任务");
        }
    }
}

有一个高级构造函数,当一组线程执行完毕后,优先执行某个方法,CyclicBarrier(int parties, Runnable barrierAction),可以用来处理特殊的任务

4、CyclicBarrier 和 CountDownLatch的区别

CountDownLatch的计数器只能使用一次,CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。比如以下代码执行完之后会返回true。

5、适用场景

CyclicBarrier可以用于多线程计算数据,最后合并计算结果的应用场景。比如一个1000万行数据的大文件,统计数据最大的钱五个数,假如我们用五个线程,将大文件分成5份,分别计算每一份中最大的数,最后,barrierAction用这些线程的计算结果,计算出整个文件中最大的五个数。

猜你喜欢

转载自blog.csdn.net/u010647035/article/details/86662077
今日推荐