怎么按apiName作为参数做一个方法限流,相信大家对方法限流的运用场景并不少见,
首先,我们就来分析方法限流的实现过程吧,
第一,方法限流必须保证线程安全,这里我们先来介绍一下什么是线程安全吧,
线程安全简单来说就是在多线程访问一个对象的时候,对象的值/状态不会因为多线程的环境而产生影响。
第二,我们需要通过时间和调用频率来限制该对象的调用,所以比较好的方法是通过一个对象
来存储每个apiName对应的调用情况时间和频率,如下我们用CacheValidate类来进行存储,
我们采用isValidate方法判断调用次数是否超限。
这时候,我们的思路就很明显了,我们需要用一个map对象进行apiName(key)和
CacheValidate(value)的存储。这时候我们的代码就能够很简单的写出来。
public class CacheValidate {
private long time;private int invokeNum;
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public int getInvokeNum() {
return invokeNum;
}
public void setInvokeNum(int invokeNum) {
this.invokeNum = invokeNum;
}
/***
校验方法是否有效
**/
public boolean isValidate(){this.invokeNum = invokeNum+1;
if(System.currentTimeMillis()/1000 <=time){
System.err.println(System.currentTimeMillis()/1000);
if(invokeNum<=60){
System.err.println("isValidate");
return true;
}else{
System.err.println("大于60次");
}
}else{
this.invokeNum = 1;
this.time=System.currentTimeMillis()/1000;
return true;
}
return false;
}
}
而我们的测试类FlowLimit就可以对方法进行调用测试了
public class FlowLimit {
private static Map<String, CacheValidate> cache = new HashMap<String, CacheValidate>();
/**
* 1. 接口限流实现 有一个API网关,出于对API接口的保护,需要建立一个流控功能,根据API名称,
* 每分钟最多只能请求指定的次数(如1000次),超过限制则这分钟内返回错误,但下一分钟又可以正常请求。 接口定义
* 对invoke方法进行调用,超过限制则return false
*
*/
public boolean invoke(String apiName) {
if(apiName==null){
return false;
}
CacheValidate cacheValidate = null;
synchronized (cache) {
cacheValidate = cache.get(apiName);
if(cacheValidate==null){
cacheValidate = new CacheValidate();
cacheValidate.setTime(System.currentTimeMillis()/1000+5);
cacheValidate.setInvokeNum(1);
cache.put(apiName, cacheValidate);
return true;
}
return cacheValidate.isValidate();
}
}
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(700);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
service.submit(getTask());
}
service.shutdown();
}
public static Runnable getTask(){
return new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
FlowLimit fLimit = new FlowLimit();
System.err.println(fLimit.invoke("aaa"));
}
}
};
}
}
至此,方法限流已经完整完成,如有疑问,欢迎联系吐槽