Java 实现滑动时间窗口限流算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.yzw.test;

import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class SlideWindow {
/**
* 队列id和队列的映射关系,队列里面存储的是每一次通过时候的时间戳,这样可以使得程序里有多个限流队列
*/
private volatile static Map<String, List<Long>> MAP = new ConcurrentHashMap<>();
private SlideWindow() {
}


public static synchronized Boolean isGo(String listId, int count, Long timeWindows) {
// 获取当前时间
long now = System.currentTimeMillis();
// 根据队列id 取出对应的 限流队列 如果没有则创建新的
List<Long> list = MAP.computeIfAbsent(listId, k -> new LinkedList<>());
// 队列没有满 说明单位时间内 次数未达到 允许通过 并将当前时间记录
if (list.size() < count) {
list.add(0, now);
return true;
}


// 通过次数大于count
if (now - list.get(count - 1) <= timeWindows) {
// 当前时间 减去 最早(第一次)添加的时间戳
// 如果计算结果小于过期时间 说明在时间内 但是count次数超了 不允许通过
return false;
} else {
// 如果大于 则说明在timeWindow内,通过的次数小于等于count
// 允许通过,并删除最早添加的时间戳,将当前时间添加到队列开始位置

list.remove(count - 1);
list.add(0, now);
return true;
}

}

public static void main(String[] args) throws InterruptedException {
while (true) {
// 任意10秒内,只允许2次通过
System.out.println(LocalTime.now().toString() + SlideWindow.isGo("ListId", 10, 2000L));
// 睡眠0-10秒
Thread.sleep(10);
}

}

}

总结: 其本质思想是转换概念,将原本问题的确定时间大小,进行次数限制。转换成确定次数大小,进行时间限制。

参考: :https://www.cnblogs.com/dijia478/p/13807826.html