實現時需要注意,用於計數的變量,自增操作應該爲原子操作。
import java.util.concurrent.atomic.AtomicLong;
public class RateLimiter {
private final static AtomicLong ZERO = new AtomicLong(0);
private AtomicLong counter = ZERO;
private static long timestamp = System.currentTimeMillis();
private long permitsPerSecond;
public RateLimiter(long permitsPerSecond) {
this.permitsPerSecond = permitsPerSecond;
}
public boolean tryAcquire() {
long now = System.currentTimeMillis();
if (now - timestamp < 1000) {
if (counter.get() < permitsPerSecond) {
counter.incrementAndGet();
return true;
} else {
return false;
}
} else {
counter = ZERO;
timestamp = now;
return false;
}
}
}
用計數器來做限流,實現簡單,並且很容易的擴展到分佈式場景中,用redis保存計數值,並設置自動過期時間。缺點就是,在計數器置0前後的極短時間裏,可能會有 2*permitsPerSecond 的突發流量。