上篇文章详细阐述了令牌桶算法的优缺点,并且针对不足之处也给出一个简单的优化方案。有了设计思路,接下来实现便相对容易很多。
首先用代码实现令牌桶算法,创建一个令牌桶类。
public class TokenBucket
{
private final long capacity;
private final long refillTokensPerOneMillis;
private AtomicLong availableTokens;
private AtomicLong lastRefillTimestamp;
public TokenBucket(long capacity, long refillTokensPerOneMillis) {
this.capacity = capacity;
this.refillTokensPerOneMillis = refillTokensPerOneMillis;
this.availableTokens = new AtomicLong(capacity);
this.lastRefillTimestamp = new AtomicLong(System.currentTimeMillis());
}
public synchronized boolean tryConsume(long numTokens)
{ refill();
if (availableTokens.get() >= numTokens)
{
availableTokens.addAndGet(-numTokens);
return true;
}
return false;
}
private void refill() {
long currentTimeMillis = System.currentTimeMillis();
long timeSinceLastRefill = currentTimeMillis - lastRefillTimestamp.get();
long tokensToRefill = timeSinceLastRefill * refillTokensPerOneMillis;
if (tokensToRefill > 0) {
availableTokens.addAndGet(tokensToRefill);
availableTokens.set(Math.min(capacity, availableTokens.get()));
lastRefillTimestamp.set(currentTimeMillis);
}
}
}
然后开启多线程使用该算法。
改进之处在于,首先注入ServerBean ,然后通过该对象调用函数查询数据库获取服务器负载值,得到负载值后,根据负载值大小,来动态调整令牌生成数量。
public void tokenMethod()
{
ServerBean serverLBIndex = serverService.getServerLBIndex();
Float min = serverLBIndex.getServerLB();
System.out.println("当前最小lb:"+serverLBIndex.getServerLB());
int flag = 1;//令牌数量可以根据实际情况动态调整
if(min > 0.8)
{
flag = 1;
}else if(min < 0.4){
flag = 3;
}else{
flag = 2;
}
System.out.println(flag);
TokenBucket tokenBucket = new TokenBucket(100, flag); // flag取代了传统固定生成令牌数量,而是动态调整
for (int i = 0; i < 10; i++) {
new Thread(() -> {
while (true) {
if (tokenBucket.tryConsume(50)) {
System.out.println(Thread.currentThread().getName() + " 执行请求");
}
else {
System.out.println(Thread.currentThread().getName() + " 请求被限流"); }
try { // 每个线程等待100毫秒后尝试再次请求
Thread.sleep(100); }
catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "线程" + i).start();
}
}
这样一个简单的优化方案便实现完成。如果有大佬有别的优化方案欢迎在评论区留言!!!