原文链接
原文写的非常好,这里只做一个简单的代码练习,方便回顾
1 固定窗口
public class FixedWindowLimiter {
/**
* 限制数量
*/
private int limitCount;
/**
* 窗口大小
*/
private int windowSize;
/**
* 上次时间
*/
private long last = System.currentTimeMillis();
/**
* 计数器
*/
private static AtomicInteger counter = new AtomicInteger();
private FixedWindowLimiter(int limitCount, int windowSize)
{
this.limitCount = limitCount;
this.windowSize = windowSize;
}
/**
* 是否拦截
* @return
*/
public synchronized boolean tryAcquire() {
long curTime = System.currentTimeMillis();
if (curTime - windowSize >= last) {
// 更新到下一个窗口
counter = new AtomicInteger();
last = System.currentTimeMillis() - windowSize;
}
if (counter.incrementAndGet() <= limitCount) {
return true;
} else {
return false;
}
}
}
2 滑动窗口
public class SlideWindowLimiter {
/**
* 窗口大小
*/
private int windowSize;
/**
* 窗口内部划分
*/
private int splitCount;
/**
* 限制数量
*/
private int limitCount;
/**
* 窗口右端点
*/
private long windowRight;
/**
* 计数器
*/
private int[] counters;
/**
* 计数器的下标
*/
private int idx;
/**
* 将这个大窗口继续分为小窗口
*/
private int gap;
/**
* 整个窗口请求数量
*/
private long totalCount = 0;
public SlideWindowLimiter(int windowSize, int splitCount, int limitCount) {
this.windowSize = windowSize;
this.splitCount = splitCount;
this.limitCount = limitCount;
gap = windowSize / splitCount;
windowRight = System.currentTimeMillis() + gap;
counters = new int[splitCount];
}
public synchronized boolean tryAcquire() {
long curTime = System.currentTimeMillis();
if (windowRight - curTime <= 0) {
do {
// 之所以要先加是因为 我们淘汰的是第一个窗口
// 利用取模的操作 +1 后如果是要往右滑动我们将最左边的小窗口移除
idx = (++ idx) % splitCount;
totalCount -= counters[idx];
counters[idx] = 0;
windowRight += gap;
} while (windowRight < curTime);
}
if (totalCount <= limitCount) {
counters[idx] ++;
totalCount ++;
return true;
} else {
return false;
}
}
}
3 漏桶算法
public class BuketLimiter {
/**
* 桶的容量
*/
private int capacity;
/**
* 桶的出水速度
*/
private int spaceTime;
/**
* 速率
*/
private int speed;
private long leakTime;
private AtomicLong counter = new AtomicLong();
public BuketLimiter(int spaceTime, int capacity, int speed) {
this.spaceTime = spaceTime;
this.capacity = capacity;
this.speed = speed;
}
public synchronized boolean tryAcquire() {
// 如果桶 为空
if (counter.get() == 0) {
leakTime = System.currentTimeMillis();
counter.incrementAndGet();
return counter.get() < capacity;
}
// 进行漏水
// 计算当前时间要漏出的数量
long leakCnt = speed * (System.currentTimeMillis() - leakTime) / spaceTime;
if (leakCnt != 0) {
long oCnt = counter.get();
oCnt -= leakCnt;
counter.set(Math.max(0, oCnt));
leakTime = System.currentTimeMillis();
}
if (counter.get() < capacity) {
counter.incrementAndGet();
return true;
} else {
return false;
}
}
}