令牌桶算法
**令牌桶(Token Bucket)**算法以一个设定的速率产生令牌(Token)并放入令牌桶,每次用户请求都得申请令牌,如果令牌不足,则拒绝请求。
令牌的数量也是有上限的。令牌的数量与时间和发放速率强相关,时间流逝的时间越长,会不断往桶里加入越多的令牌,如果令牌发放的速度比申请速度快,令牌桶会放满令牌,直到令牌占满整个令牌桶。
- 想象一个固定容量的'令牌桶',系统按固定速率向桶中添加令牌(比如每秒放 10 个)。
- 当有请求到达时,需要从桶中获取一个令牌才能被处理;如果桶中没有令牌,请求则被丢弃或排队。
- 令牌桶的容量决定了允许的最大突发流量(比如桶容量 100,意味着最多允许 100 个请求同时突发)。
关键概念:
- 令牌生成速率(r):每秒生成的令牌数量(控制长期平均速率)。
- 令牌桶容量(b):桶最多能存放的令牌数(控制最大突发流量)。
- 令牌消耗:每个请求消耗 1 个令牌(可调整为按请求大小消耗)。

特点:
- 平滑流量:通过固定速率生成令牌,限制长期平均请求速率。消费速度不固定。
- 允许突发:桶中累积的令牌可应对短时间的突发流量(只要不超过桶容量)。
- 灵活性:可调整令牌生成速率和桶容量,适配不同场景。
Java 代码实现
/**
* 令牌桶限流算法
*/
public class TokenBucketLimiter {
// 桶的容量
private final int capacity;
// 令牌生成速度 (个/秒)
private final int rate;
// 当前令牌数量
private final AtomicInteger tokens;
/**
* 构造函数
* @param capacity 桶的容量
* @param rate 令牌生成速度 (个/秒)
*/
public TokenBucketLimiter(int capacity, int rate) {
this.capacity = capacity;
.rate = rate;
.tokens = (capacity);
startTokenProducer();
}
{
Executors.newSingleThreadScheduledExecutor();
scheduledThreadPool.scheduleAtFixedRate(() -> {
tokens.getAndUpdate(current -> Math.min(capacity, current + rate));
}, , , TimeUnit.SECONDS);
}
{
tryAcquire();
}
{
(numberOfTokens <= ) {
();
}
() {
tokens.get();
(current < numberOfTokens) {
;
}
(tokens.compareAndSet(current, current - numberOfTokens)) {
;
}
}
}
{
tokens.get();
}
}



