
思想
定义一个令牌桶(Token_Bucket),以一定的速度向桶里投掷令牌
(now - lastThrowTime) * rate
业务方在处理请求前先去令牌桶获取令牌(acquire),如果获得令牌成功,则进行后续逻辑,否则就丢弃请求或者将请求放置到等待队列。
代码
package cn.melonkid.commons.lang;
import java.lang.reflect.Field; import java.util.concurrent.locks.ReentrantLock; import sun.misc.Unsafe;
public class RateLimiter {
private int tokenVolume;
private final int rate = 1;
private long lastRefreshTime;
private long currTokens = 0;
private static long currTokensOffset;
private ReentrantLock lock = new ReentrantLock();
private static Unsafe unsafe;
static { try { try { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); unsafe = (Unsafe) field.get(null); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } currTokensOffset = unsafe.objectFieldOffset( RateLimiter.class.getDeclaredField("currTokens")); } catch (NoSuchFieldException e) { e.printStackTrace(); } }
public RateLimiter(int tokenVolume) { this.tokenVolume = tokenVolume; this.currTokens = tokenVolume; this.lastRefreshTime = System.currentTimeMillis(); }
public boolean acquire() { lock.lock(); try { long currTimestamp = System.currentTimeMillis(); int newTokens = (int) ((currTimestamp - lastRefreshTime) * rate / 1000); currTokens = Math.min(tokenVolume, (newTokens + currTokens)); if (newTokens > 0) { lastRefreshTime = currTimestamp; }
if (currTokens <= 0) { return false; }
return compareAndSwap(currTokens, currTokens - 1); } finally { lock.unlock(); } }
public boolean compareAndSwap(long except, long target) { return unsafe.compareAndSwapLong(this, currTokensOffset, except, target); }
}
|