一、时间窗口固定
使用map存储,key为唯一值,value为一个实体,存着开始时间和次数,取出来判断是否为空,如果为空就新建一个对象进去并且如果不为空并且当前时间-取出来的时间>最大时间限制值,重新赋值value,value=当前时间,次数1,返回可以请求,如果上述条件不满足,则判断次数是否>=最大限制,如果大于就返回不让请求,如果小于,则次数加1返回可以请求。
缺点:时间快结束和时间开始的时候会在xxx区间的时候大于某段时间内最请求 所以看下面时间滑动窗口解决
import java.util.HashMap;
import java.util.Map;
public class RequestLimiter {
private static final int MAX_REQUESTS = 5; // 最大请求次数
private static final long MAX_TIME_WINDOW = 60 * 1000; // 最大时间窗口,单位:毫秒
private Map<String, RequestEntity> requestMap = new HashMap<>();
public boolean canMakeRequest(String key) {
long currentTime = System.currentTimeMillis();
RequestEntity entity = requestMap.get(key);
if (entity == null) {
// 如果唯一标识符不存在于Map中,创建一个新的实体对象
entity = new RequestEntity(currentTime, 1);
requestMap.put(key, entity);
return true;
} else {
// 如果唯一标识符存在
long elapsedTime = currentTime - entity.getStartTime();
if (elapsedTime > MAX_TIME_WINDOW) {
// 如果时间窗口过期,重新设置实体对象的值
entity.setStartTime(currentTime);
entity.setCount(1);
return true;
} else if (entity.getCount() < MAX_REQUESTS) {
// 如果在时间窗口内,但请求次数未达到限制,增加次数
entity.setCount(entity.getCount() + 1);
return true;
} else {
// 如果次数已达到限制,不允许请求
return false;
}
}
}
public static void main(String[] args) {
RequestLimiter requestLimiter = new RequestLimiter();
String key = "user123";
for (int i = 0; i < 10; i++) {
if (requestLimiter.canMakeRequest(key)) {
System.out.println("Request allowed");
} else {
System.out.println("Request not allowed");
}
}
}
}
class RequestEntity {
private long startTime;
private int count;
public RequestEntity(long startTime, int count) {
this.startTime = startTime;
this.count = count;
}
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
二、时间滑动窗口
public class TimeSlidingWindow {
private Deque<Long> window; // 存储时间戳的双端队列
private int windowSize; // 窗口大小
private long windowDuration; // 窗口持续时间(毫秒)
public TimeSlidingWindow(int windowSize, long windowDuration) {
this.window = new ArrayDeque<>();
this.windowSize = windowSize;
this.windowDuration = windowDuration;
}
public Boolean addTimestamp(long timestamp) {
// 移除超出窗口持续时间的时间戳
long threshold = timestamp - windowDuration;
//如果不为空&&拿出第一比较 超出窗口持续时间的时间戳
while (!window.isEmpty() && window.peekFirst() < threshold) {
//移除
window.pollFirst();
}
if(window.size() >= windowSize) {
return false;
}
// 添加新的时间戳到窗口末尾
window.offerLast(timestamp);
return true;
}
}