- QPS控制器实现类代码:
/**
* @desc QPS控制器
* @author visy.wang
* @date 2020/9/29 10:13
*/
public class QPSCtrl {
/**
* QPS值
*/
private int qps;
/**
* 一个周期内的调用次数
*/
private int count;
/**
* 一个周期的起始时间(时间戳)
*/
private long startTime;
/**
* 周期长度(毫秒)
*/
private static final int PERIOD = 1000;
/**
* 通过指定QPS创建控制器(内部使用)
* @param qps QPS值
*/
private QPSCtrl(int qps){
this.qps = qps;
}
/**
* 创建QPSCtrl实例
* @param qps QPS值
* @return Object
*/
public static QPSCtrl create(int qps){
return new QPSCtrl(qps);
}
/**
* 开始下一个周期
* @param startTime 起始时间戳
*/
private void next(long startTime){
this.count = 1;
this.startTime = startTime;
//测试用,可删除
System.out.println(" ");
}
/**
* qps控制(线程阻塞,休眠实现)
* 适用于多线程环境
*/
public synchronized void ctrl(){
long now = System.currentTimeMillis();
long duration = now - this.startTime;
if(duration < PERIOD){
if(this.count < this.qps){
this.count ++;
}else{
try{
Thread.sleep(PERIOD - duration);
}catch (InterruptedException e){
e.printStackTrace();
}
this.next(System.currentTimeMillis());
}
}else{
this.next(now);
}
}
}
*使用(测试):
/**
* @desc QPS控制器测试
* @author visy.wang
* @date 2020/9/29 10:25
*/
public class TestQPS {
/**
* 在多线程环境下,请确保拿到的QPSCtrl对象是同一个,
* 建议在此处初始化,当然也可用别的方式创建(但需保证是同一个)
* 不同的QPSCtrl对象是彼此独立的
*/
private static QPSCtrl qpsCtrl1 = QPSCtrl.create(2);
private static QPSCtrl qpsCtrl2 = QPSCtrl.create(3);
public void test1(int i){
//调用ctrl()来实现QPS的控制
qpsCtrl1.ctrl();
System.out.print(i+"(I) ");
}
public void test2(int i){
//超出QPS值会阻塞在这里,直到下一个周期
qpsCtrl2.ctrl();
System.out.print(i+"(II) ");
}
public static void main(String[] args) {
TestQPS testQPS = new TestQPS();
new Thread(()->{
for(int i=1; i<=6; i++){
testQPS.test1(i);
}
}).start();
new Thread(()->{
for(int i=7; i<=12; i++){
testQPS.test1(i);
}
}).start();
new Thread(()->{
for(int i=13; i<=18; i++){
testQPS.test2(i);
}
}).start();
}
}
- 输出:
7(I) 8(I)
13(II) 14(II) 15(II)
9(I) 10(I)
16(II) 17(II) 18(II)
11(I) 1(I)
12(I) 2(I)
3(I) 4(I)
5(I) 6(I)