CyclicBarrier是什么?如何使用?

XIAO 2020-05-05 15:14:37 java常见问答 6206

对java软件开发行业感兴趣的小伙伴,你们了解过CyclicBarrier吗?知道CyclicBarrier应该如何使用吗?下面有兴趣的朋友一起来看看吧。

CyclicBarrier其实是java推出的一个并发编程工具,它的作用是在多个线程之间协同工作。比如说线程约定到达某个点,到达这个点之后的线程就都停下来,直到最后一个线程也到达了这个点之后,所有的线程才会得到释放。常用的场景是:多个worker线程,每个线程都在循环地做一部分的工作,并且在最后用cyclicBarrier.await()方法设下约定点,当最后一个线程做完了工作也到达约定点之后,所有线程的得到释放,才开始下一轮的工作。也就是下面这样的:

while (!done())
{
    //working
    cyclicBarrier.await();
}
CyclicBarrier支持一个回调函数, 每次当一轮工作结束后, 在下一轮工作开始前, 这个回调函数呢都会被调用一次。
但是, 使用CyclicBarrier必须准守最佳实践的使用方法, 不然的话, 就可能达不到想要的效果。 比如说, 下面这样, 就是一种典型的错误使用方法:
private void process(CyclicBarrier cyclicBarrier)
{
    final int n = 100;
    Runnable worker = new Runnable()
    {
        @Override
        public void run()
        {
            try
            {
                //模拟工作
                Thread.sleep(3000);
            }
            catch (InterruptedException ex)
            {
                ex.printStackTrace();
            }
            try
            {
                cyclicBarrier.await();
            }
            catch (BrokenBarrierException | InterruptedException ex)
            {
                ex.printStackTrace();
            }
        }
        System.out.println("Worker is done");
        System.out.println("Thread of Worker is " + Thread.currentThread()
            .getId());
    };
    for (int i = 0; i < n; i++)
    {
        Thread t1 = new Thread(worker);
        Thread t2 = new Thread(worker);
        t1.start();
        t2.start();
    }
}

在上面的代码里面,工作不是在worker线程中循环,而是在开启工作的线程中循环,这也就是说,它会不断地开启新的worker线程。这会导致的一个问题就是,上一轮的回调还没执行完成,下一轮的工作就已经开始了。

CyclicBarrier支持一个可选的Runnable命令,每个屏障点运行一次,在派对中的最后一个线程到达之后,但在任何线程释放之前。 在任何一方继续进行之前,此屏障操作对更新共享状态很有用。

其实现原理:在CyclicBarrier的内部定义了一个Lock对象,每当一个线程调用await方法时,将拦截的线程数减1,然后判断剩余拦截数是否为初始值parties,如果不是的话,就进入Lock对象的条件队列等待。如果是就执行barrierAction对象的Runnable方法,然后将锁的条件队列中的所有线程放入锁等待队列中,这些线程会依次的获取锁、释放锁。

构造方法。CyclicBarrier(int parties),创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待它时,它将跳闸,并且当屏障跳闸时不执行预定义的动作。

CyclicBarrier(int parties, Runnable barrierAction),创建一个新的 CyclicBarrier ,当给定数量的线程(线程)等待时,它将跳闸,当屏障跳闸时执行给定的屏障动作,由最后一个进入屏障的线程执行。

方法如下所示:

int await() 等待所有 parties已经在这个障碍上调用了 await 。

int await(long timeout, TimeUnit unit) 等待所有 parties已经在此屏障上调用 await ,或指定的等待时间过去。

int getNumberWaiting() 返回目前正在等待障碍的各方的数量。

int getParties() 返回旅行这个障碍所需的parties数量。

boolean isBroken() 查询这个障碍是否处于破碎状态。

void reset() 将屏障重置为初始状态。

好了,以上就是本篇文章的所有内容了,如果你还想了解更多java架构师信息,记得来关注本站消息哦。