最近在做接口限流时涉及到了一个有意思问题,牵扯出了关于concurrentHashMap的一些用法,以及CAS的一些概念。限流算法很多,我主要就以最简单的计数器法来做引。先抽象化一下需求:统计每个接口访问的次数。一个接口对应一个url,也就是一个字符串,每调用一次对其进行加一处理。可能出现的问题主要有三个:
- 多线程访问,需要选择合适的并发容器
- 分布式下多个实例统计接口流量需要共享内存
- 流量统计应该尽可能不损耗服务器性能
但这次的博客并不是想描述怎么去实现接口限流,而是主要想描述一下遇到的问题,所以,第二点暂时不考虑,即不使用redis。
说到并发的字符串统计,立即让人联想到的数据结构便是ConcurrentHashpMap<String,Long> urlCounter;
如果你刚刚接触并发可能会写出如代码清单1的代码
代码清单1:
public class CounterDemo1 {
private final Map<String, Long> urlCounter = new ConcurrentHashMap<>();
//接口调用次数+1
public long increase(String url) {
Long oldValue = urlCounter.get(url);
Long newValue = (oldValue == null) ? 1L : oldValue + 1;
urlCounter.put(url, newValue);
return newValue;
}
//获取调用次数
public Long getCount(String url){
return urlCounter.get(url);
}
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(10);
final CounterDemo1 counterDemo = new CounterDemo1();
int callTime = 100000;
final String url = "http://localhost:8080/hello";
CountDownLatch countDownLatch = new CountDownLatch(callTime);
//模拟并发情况下的接口调用统计
for(int i=0;i<callTime;i++){
exec