当前位置: 首页>后端>正文

限流器的简单实现

这是阿里一面的一道设计题,限制一个用户一秒只能访问100次。

isAllow来判断用户是否可以访问(超过频率限制就不行)

思路是一个100容量的容器记录每一次访问的时间,只要没有一百次就是可以访问。

超过一百次则统计第一个和第101个的时间差是非小于1秒,小于一秒超过频率限制,返回false

没超过就删除第一个加入最新的一个返回true,保证每次统计的都是最新的100次访问就行。

原本的第一版实现使用的是CopyOnWriteArrayList<Long>?后面改为为PriorityBlockingQueue<long>;

原因是CopyOnWriteArrayList<Long>?记录的时间在多线下记录的顺序未必是时间升序(第一个未必是最早访问的时间),PriorityBlockingQueue<long>的peek每次都会返回队列中时间最小的元素(最早访问的时间)这样就能确保统计的是正确的时间。

``` java?

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.PriorityBlockingQueue;

import java.util.concurrent.locks.ReentrantLock;

public class Solution56 {

static ConcurrentHashMap<String, PriorityBlockingQueue<Long>> count = new ConcurrentHashMap<String, PriorityBlockingQueue<Long>>();

private final ReentrantLock lock = new ReentrantLock();

boolean isAllow(String clientId) {

lock.lock();

try {

while (count.get(clientId) == null) {

count.put(clientId, new PriorityBlockingQueue<Long>());

}

} finally {

lock.unlock();

// TODO: handle finally clause

}

long currentTimeMillis = System.currentTimeMillis();

PriorityBlockingQueue<Long> priorityQueue = count.get(clientId);

if (priorityQueue.size() >= 100) {

if (currentTimeMillis - priorityQueue.peek() <= 1000) {

priorityQueue.offer(currentTimeMillis);

if (priorityQueue.size() > 100) {

priorityQueue.poll();

}

return false;// 一百次少于一秒

} else {

priorityQueue.offer(currentTimeMillis);

if (priorityQueue.size() > 100) {

priorityQueue.poll();

}

// 一百次多于一秒删除第一个重新统计

return true;

}

}

priorityQueue.offer(currentTimeMillis);

return true;

}

public static void main(String[] args) {

Solution56 solution56 = new Solution56();

List<Thread> list = new ArrayList<Thread>();

for (int i = 0; i < 101; i++) {

Thread thread = new Thread(() -> {

if (!solution56.isAllow("yzq")) {

System.out.println(false);

}

});

list.add(thread);

thread.start();

}

}

}

```?


https://www.xamrdz.com/backend/3fu1944807.html

相关文章: