CyclicBarrier类在性能测试中应用
CyclicBarrier
也叫同步屏障,在JDK1.5
被引入,可以让一组线程达到一个屏障时被阻塞,直到最后一个线程达到屏障时,所以被阻塞的线程才能继续执行。在执行很多个任务,但是这些任务中间某个节点需要等到其他任务都执行到固定的节点才能继续进行,先到达的线程会一直等待所有线程到达这个节点。在性能测试中,经常会遇到N多个用户同时在线的场景,一般处理起来都是先让这N多个用户登录,然后保持登录状态,然后去并发请求。这个场景下CyclicBarrier
就能完美解决我们的需求。
基本介绍
CyclicBarrier
类常用的构造方法有两个:1、只有一个int
类型的参数,表示参加等待的线程数,这一点跟CountDownLatch
类一样;2、构造方法多了一个Runnable
参数,这个表示所有线程都到达等待节点后执行的线程任务,网上大多数用赛跑的发令枪做比喻,很形象。当所有线程都到达准备好之后,发令枪就响了。
/**
* 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
;如果等待过程中,其它等待的线程被中断,或者其它线程等待超时,或者该barrier
被reset
,或者当前线程在执行barrier
构造时注册的action
时因为抛出异常而失败,则抛出BrokenBarrierException
。
reset()
该方法会将该barrier
重置为它的初始状态,并使得所有对该barrier
的await
调用抛出BrokenBarrierException
。
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秒的等待,出发超时报错的。
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
参数的调用的话,可以放开超时,控制台输出如下:
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
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【tensorflow2.0】训练模型的三种方法
- 用C++跟你聊聊“建造者模式”
- 【tensorflow2.0】使用TPU训练模型
- 用C++跟你聊聊“外观模式”
- 【tensorflow2.0】使用tensorflow-serving部署模型
- 用C++跟你聊聊“模板方法模式”
- 用C++跟你聊聊“原型模式” (复制/拷贝构造函数)
- 【numpy】生成图片格式的数据
- 【numpy】新版本中numpy(numpy>1.17.0)中的random模块
- 用C++跟你聊聊“代理模式”
- mybatis与spring整合步骤以及自己遇到的错误
- 用C++跟你聊聊“装饰者模式”
- 【python实现卷积神经网络】激活函数的实现(sigmoid、softmax、tanh、relu、leakyrelu、elu、selu、softplus)
- 【python实现卷积神经网络】损失函数的定义(均方误差损失、交叉熵损失)
- 【python实现卷积神经网络】优化器的实现(SGD、Nesterov、Adagrad、Adadelta、RMSprop、Adam)