1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
| public class SlidingWindowRateLimit implements RateLimit,Runnable{ private Integer limitCount;
private AtomicInteger passCount;
private Integer windowSize;
private long windowPeriod; private TimeUnit timeUnit; private Window[] windows; private volatile Integer windowIndex = 0; private Lock lock = new ReentrantLock();
public SlidingWindowRateLimit(Integer limitCount) { this(limitCount,5, 200, TimeUnit.MILLISECONDS); }
public SlidingWindowRateLimit(Integer limitCount, Integer windowSize, long windowPeriod, TimeUnit timeUnit) { this.limitCount = limitCount; this.windowSize = windowSize; this.windowPeriod = windowPeriod; this.timeUnit = timeUnit; this.passCount = new AtomicInteger(0); this.initWindows(windowSize); this.startRestTask(); }
private ScheduledExecutorService scheduledExecutorService; private void startRestTask(){ scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); scheduledExecutorService.scheduleAtFixedRate(this, 0, windowPeriod, timeUnit); }
private void initWindows(Integer windowSize){ windows = new Window[windowSize]; for (int i = 0; i < windowSize; i++){ windows[i] = new Window(); } }
@Override public boolean canPass() throws RuntimeException { lock.lock();; if(passCount.get() > limitCount){ throw new RuntimeException(); } windows[windowIndex].passCount.incrementAndGet(); passCount.incrementAndGet(); lock.unlock(); return true; }
@Override public void run() { Integer curIndex = (windowIndex + 1) % windowSize; Integer count = windows[curIndex].passCount.getAndSet(0); windowIndex = curIndex; passCount.addAndGet(-count); }
public static void main(String[] args) throws InterruptedException { SlidingWindowRateLimit slidingWindowRateLimit = new SlidingWindowRateLimit(10); for(int i = 0; i < 10000; i++){ Thread.sleep(100); if(slidingWindowRateLimit.canPass()){ System.out.println("通过第【" + i + "】个请求"); } } } }
class Window{ public AtomicInteger passCount; public Window(){ this.passCount = new AtomicInteger(0); } }
|