我正在尝试实施令牌桶速率限制器。下面是我写的基本代码,但没有得到预期的结果。好像我遗漏了一些东西,或者我还没有完全理解如何在 java 中使用线程函数。有人可以帮助我寻找正确的方向吗?
public class RateLimiterTokenBucket implements RateLimiter, Runnable{
Integer capacity;
Integer frequencyInMilliseconds;
Integer currentCapacity;
public RateLimiterTokenBucket(Integer frequencyInMilliseconds,Integer capacity) {
this.frequencyInMilliseconds = frequencyInMilliseconds;
this.capacity = capacity;
this.currentCapacity = capacity;
}
@Override
public boolean consume() {
synchronized (currentCapacity) {
if(currentCapacity <= 0) return false;
--currentCapacity;
return true;
}
}
@Override
public void run() {
synchronized (currentCapacity) {
OffsetDateTime t = OffsetDateTime.now();
while(true) {
if(OffsetDateTime.now().isAfter(t.plus(frequencyInMilliseconds, ChronoUnit.MILLIS))){
if(currentCapacity<capacity){
System.out.println("token added");
++currentCapacity;
}
t=OffsetDateTime.now();
}
}
}
}
}
主课
public static void main(String[] args) {
RateLimiter rl = new RateLimiterTokenBucket(10,5);
Thread t = new Thread((Runnable) rl);
t.start();
while(true){
if(rl.consume()) {
System.out.println(OffsetDateTime.now()+" ---> true");
}
}
}
刚开始
2023-04-29T19:30:54.685553+05:30 ---> true
token added
作为输出 两个线程 main 和 t1 仍在运行
run
方法的整个主体都在同步块中。实际上 always 是一个错误。在线程完全完成并且 run
方法返回之前,您不希望任何其他线程能够执行什么操作?
此外,
synchronized(currentCapacity)
看起来也是一个错误,因为您的程序将不同的对象分配给currentCapacity
。当一个线程在 Integer(5)
上同步而另一个线程在 Integer(4)
上同步时,这意味着什么?如果作为一般规则,除非 synchronized(foo)
是一个 foo
变量,否则您可以避免犯这个错误。
另请注意:您的主线程在等待下一个令牌时(即,它会消耗 CPU 时间)。这并非 always 坏事,但通常 如果您正在运行的主机没有保留专用于该线程的 CPU,并且有其他线程准备好-运行并等待轮到他们使用 CPU。