前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CyclicBarrier类在性能测试中应用

CyclicBarrier类在性能测试中应用

作者头像
FunTester
发布2020-08-05 10:00:29
1.4K0
发布2020-08-05 10:00:29
举报
文章被收录于专栏:FunTesterFunTester

CyclicBarrier也叫同步屏障,在JDK1.5被引入,可以让一组线程达到一个屏障时被阻塞,直到最后一个线程达到屏障时,所以被阻塞的线程才能继续执行。在执行很多个任务,但是这些任务中间某个节点需要等到其他任务都执行到固定的节点才能继续进行,先到达的线程会一直等待所有线程到达这个节点。在性能测试中,经常会遇到N多个用户同时在线的场景,一般处理起来都是先让这N多个用户登录,然后保持登录状态,然后去并发请求。这个场景下CyclicBarrier就能完美解决我们的需求。

基本介绍

CyclicBarrier类常用的构造方法有两个:1、只有一个int类型的参数,表示参加等待的线程数,这一点跟CountDownLatch类一样;2、构造方法多了一个Runnable参数,这个表示所有线程都到达等待节点后执行的线程任务,网上大多数用赛跑的发令枪做比喻,很形象。当所有线程都到达准备好之后,发令枪就响了。

代码语言:javascript
复制

    /**
     * Creates a new {@code CyclicBarrier} that will trip when the
     * given number of parties (threads) are waiting upon it, and
     * does not perform a predefined action when the barrier is tripped.
     *
     * @param parties the number of threads that must invoke {@link #await}
     *        before the barrier is tripped
     * @throws IllegalArgumentException if {@code parties} is less than 1
     */
    public CyclicBarrier(int parties) {
        this(parties, null);
    }


       /**
     * Creates a new {@code CyclicBarrier} that will trip when the
     * given number of parties (threads) are waiting upon it, and which
     * will execute the given barrier action when the barrier is tripped,
     * performed by the last thread entering the barrier.
     *
     * @param parties the number of threads that must invoke {@link #await}
     *        before the barrier is tripped
     * @param barrierAction the command to execute when the barrier is
     *        tripped, or {@code null} if there is no action
     * @throws IllegalArgumentException if {@code parties} is less than 1
     */
    public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }

重要方法

使用方法比较简单,构造方法完成后,之后一个方法await(),这个方法用来表示到达节点后开始等待其他线程到达,同样的,还有一个重载方法,增加了超时设置,两个参数:1、时间;2、时间单位。如果该方法报了超时异常,那么其他等待线程到达这个方法后会报BrokenBarrierException这个异常。由于CyclicBarrier对象的await()方法在同一线程中是可以多次调用的,相当于任务分成了很多阶段,一旦某一个线程的某一个任务阶段报错,会导致其他线程同样的任务阶段都报错,进而可能导致所有现成任务报错失败。

如果当前调用是最后一个调用,则唤醒所有其它的线程的等待并且如果在构造CyclicBarrier时指定了action,当前线程会去执行该action,然后该方法返回该线程调用await的次序(getParties()-1说明该线程是第一个调用await的,0说明该线程是最后一个执行await的),接着该线程继续执行await后的代码;如果该调用不是最后一个调用,则阻塞等待;如果等待过程中,当前线程被中断,则抛出InterruptedException;如果等待过程中,其它等待的线程被中断,或者其它线程等待超时,或者该barrierreset,或者当前线程在执行barrier构造时注册的action时因为抛出异常而失败,则抛出BrokenBarrierException

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

代码语言:javascript
复制
       public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }

    public int await(long timeout, TimeUnit unit)
        throws InterruptedException,
               BrokenBarrierException,
               TimeoutException {
        return dowait(true, unit.toNanos(timeout));
    }

    public void reset() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            breakBarrier();   // break the current generation
            nextGeneration(); // start a new generation
        } finally {
            lock.unlock();
        }
    }
    

实践

下面是我写的一个测试Demo,第一个线程我估计写了1秒的等待,出发超时报错的。

代码语言:javascript
复制
  public static void main(String[] args) {
        CyclicBarrier very_good = new CyclicBarrier(2, new Runnable() {
            @Override
            public void run() {
                logger.warn("very good");
            }
        });

        new Thread(() -> {
            logger.info("111111111");
            try {
                very_good.await(1, TimeUnit.SECONDS);
                sleep(1);
                very_good.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(() -> {
            sleep(2);
            logger.info("222222222");
            try {
                very_good.await();
                very_good.await();
//                very_good.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }).start();

        testOver();
    }

如果想实验Runnable参数的调用的话,可以放开超时,控制台输出如下:

代码语言:javascript
复制
INFO-> 当前用户:fv,IP:192.168.0.107,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.15.6
INFO-> 111111111
INFO-> 222222222
WARN-> very good
WARN-> very good

Process finished with exit code 0
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基本介绍
  • 重要方法
  • 实践
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档