关于java:Java多线程如何正确使用循环栅栏CyclicBarrier

64次阅读

共计 1944 个字符,预计需要花费 5 分钟才能阅读完成。

前言

本篇文章的代码示例已放到 github 上,Git 地址为:advance(记录每一个学习过程),大家把代码下载下来之后,全局搜寻一些要害代码,即可找到该文章的源码。

大家感觉有用的话,麻烦点个 star👍再走呗!

应用场景

设想一个这样的场景,咱们在打王者光荣 / 英雄联盟的时候,都会有一个匹配机制,须要 10 集体都加载实现后,大家能力一起进入游戏,不然会呈现大家进入游戏的工夫不统一的状况,这个时候就能够应用 CyclicBarrier 来实现。

基本原理

应用 CyclicBarrier 的线程被叫做参与方,它的外部保护了一个显式锁。参与方只须要执行 await() 就能够参加期待,此时这些线程会被暂停。当最初一个线程执行 await() 办法后,其余被暂停的线程都会被唤醒,而最初一个线程不会被暂停。

罕用办法

// 结构器,定义参加的线程数
CyclicBarrier cyclicBarrier = new CyclicBarrier(10);

// 结构器,能够传入跳栅后须要执行的线程
public CyclicBarrier(int parties, Runnable barrierAction);

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

// 进行期待
int await()

// 进行期待,同时具备超时工夫
public int await(long timeout, TimeUnit unit)

应用示例

定义玩家运行程序

public class CyclicBarrierRunnable implements Runnable{
    private CyclicBarrier cyclicBarrier;
    private int number;

    public CyclicBarrierRunnable(CyclicBarrier cyclicBarrier, int number) {
        this.cyclicBarrier = cyclicBarrier;
        this.number = number;
    }

    @Override
    public void run() {System.out.println("玩家" + number + "号正在加载游戏...");
        try {TimeUnit.SECONDS.sleep(2);
            cyclicBarrier.await();} catch (Exception e) {System.out.println("线程执行呈现问题");
        }
        System.out.println("玩家" + number + "号加载实现。");
    }
}

定义主程序

public class Main {public static void main(String[] args) throws InterruptedException, BrokenBarrierException {CyclicBarrier cyclicBarrier = new CyclicBarrier(10);
        // 获取参与方的总数
        System.out.println("参与方的总数为:" + cyclicBarrier.getParties());
        // 获取此时期待的线程数
        System.out.println("此时期待的线程数为:" + cyclicBarrier.getNumberWaiting());

        for (int i = 0; i < 10; i++){CyclicBarrierRunnable runnable = new CyclicBarrierRunnable(cyclicBarrier, i);
            new Thread(runnable).start();}
    }
}

运行后果

执行阐明

主线程每隔 2 秒会启动一个子线程执行,子线程打印“筹备执行”后,会调用 await() 办法进行期待,从后果咱们能够看出:当最初一个 CyclicBarrier.await() 办法被执行后,所有的期待线程同时被唤醒,同时开始执行。

外部原理

CyclicBarrier 外部应用了一个条件变量 trip 来实现期待 / 告诉。

CyclicBarrier 外部实现应用了分代的概念用于示意 CyclicBarrier 实例是能够重复使用的。

除最初一个线程外的任何一个参与方都相当于一个期待线程,这些线程所应用的爱护条件是:“以后分代内,尚未执行 await 办法的参与方个数为 0”。await() 办法每被执行一次,相应实例的 parties 值会缩小 1. 最初一个线程相当于告诉线程,它执行 await() 会使相应实例的 parties 的值变为 0,此线程会先执行 barrierAction.run(),而后再执行 trip.signalAll() 来唤醒所有期待线程。

注意事项

  1. 应用 reset() 办法将屏障置为初始状态时,如果所有参与者目前都在屏障处期待,则将他们唤醒,同时抛出一个 BrokenBarrierException 异样

正文完
 0