限制一个线程在特定时间段内只能成功执行一次请求的常用实现方式是利用令牌桶(Token Bucket)方式或者漏桶(Leaky Bucket)方式。
如下面是一个简单的令牌桶例子,我们使用Guava提供的RateLimiter类:
import com.google.common.util.concurrent.RateLimiter;
public class RequestLimiter {
// RateLimiter.create(1.0)表示1秒只允许1次请求,如果是0.3表示3秒只允许1次请求
private RateLimiter limiter = RateLimiter.create(1.0);
public void access() {
if (limiter.tryAcquire()) { // tryAcquire尝试获取令牌,如果获取到则立即返回true,否则返回false
// 处理请求
System.out.println("access success");
} else {
System.out.println("access denied");
}
}
}可以在每个请求到达时,调用RequestLimiter的access方法,如果该方法返回access denied,说明该请求被限流。
注意:以上代码每次只能处理单个线程请求,如果是多线程请求,则需要确保RequestLimiter被设计成单例,或者使用其他方式确保limiter同一时刻只被一个线程使用。
另外还可以通过使用分布式限流,比如使用Redis,这样可以处理分布式场景下的限流。
再者服务器或者API网关一般也提供了限流策略,比如Nginx,Zuul等。
以上都是对于服务器端的限流策略,如果在客户端需要做限制,可以设计一个定时器或者标志位,当请求发送后设定一个定时器或者将标志位设为阻塞状态,过一段时间后,定时器到时或者将标志位设为非阻塞,期间所有的请求都被拒绝。