需求描述
写一个1秒两个的限流工具类,2r/s
使用semaphore
代码实现-类似令牌桶算法
public class LimitHelper {
private int maxLimit;
private Semaphore semaphore;
private int timeoutSeconds;
public LimitHelper(int maxLimit, int timeoutSeconds) {
this.maxLimit = maxLimit;
semaphore = new Semaphore(maxLimit);
this.timeoutSeconds = timeoutSeconds;
this.autoRelease();
}
/**
* 每秒钟释放两个信号出来
*/
private void autoRelease() {
new Thread(() -> {
try {
while (true) {
TimeUnit.SECONDS.sleep(timeoutSeconds);
if (!semaphore.tryAcquire(1)) {
// 无信号了
semaphore.release(maxLimit);
}else {
// 池中有信号,并且消耗了一个,释放一个补偿
semaphore.release(1);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
public boolean acquire() {
try {
return semaphore.tryAcquire(1, timeoutSeconds, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
LimitHelper limitHelper = new LimitHelper(2, 1);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
while (true) {
if (limitHelper.acquire()) {
System.out.println( System.currentTimeMillis() / 1000+ " " + Thread.currentThread().getName() + " 获取到令牌");
try {
// 业务处理
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else {
System.out.println(System.currentTimeMillis() / 1000 + " "+Thread.currentThread().getName() + " 被限流了");
}
}
}).start();
}
}
}
结果演示
滑动窗口算法实现
如上图,红色是被限流的请求事件,蓝色是允许的请求事件。
代码实现
public class LimitHelper2 {
/**
* 次数
*/
private int maxRate;
/**
* 多久时间内
*/
private int rangeTimeSeconds;
/**
* 历史记录
*/
private volatile LinkedList<Long> timeRecord;
public LimitHelper2(int maxRate, int rangeTimeSeconds) {
this.maxRate = maxRate;
this.rangeTimeSeconds = rangeTimeSeconds;
timeRecord = new LinkedList<>();
}
/**
* 2r/s 限流实现
*/
private synchronized boolean acquire() {
long now = System.currentTimeMillis();
long min = now - (rangeTimeSeconds * 1000L);
if (timeRecord.isEmpty()) {
timeRecord.addLast(now);
return true;
}
// 不为空并且size >= maxRate
int count = 0;
if (timeRecord.size() >= maxRate) {
LinkedList<Long> newRecords = new LinkedList<>();
for (int i = 0; i < maxRate; i++) {
Long beforeHappenTime = timeRecord.pollLast();
if (beforeHappenTime == null) {
timeRecord.addLast(now);
System.out.println("before时间为null");
return true;
}
newRecords.addFirst(beforeHappenTime);
if (beforeHappenTime.compareTo(min) >= 0) {
count++;
} else {
break;
}
}
timeRecord = newRecords;
if (count >= maxRate) {
return false;
} else {
timeRecord.addLast(now);
return true;
}
} else {
timeRecord.add(now);
return true;
}
}
public static void main(String[] args) {
// 1秒2次 限流
LimitHelper2 limiter = new LimitHelper2(4, 1);
for (int i = 0; i < 5; i++) {
new Thread(() -> {
while (true) {
if (limiter.acquire()) {
try {
System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + " 执行任务");
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println(System.currentTimeMillis() + " " + Thread.currentThread().getName() + " 被限流");
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}).start();
}
}
}
结果演示
4r/s