@Test public void testRateLimiterConcurrency() { int numWorkers = ForkJoinPool.getCommonPoolParallelism(); int creditsPerWorker = 1000; MockClock clock = new MockClock(); RateLimiter limiter = new RateLimiter(1, numWorkers * creditsPerWorker, clock); AtomicInteger count = new AtomicInteger(); for (int w = 0; w < numWorkers; ++w) { ForkJoinPool.commonPool().execute(() -> { for (int i = 0; i < creditsPerWorker * 2; ++i) { if (limiter.checkCredit(1)) { count.getAndIncrement(); } } }); } ForkJoinPool.commonPool().awaitQuiescence(1, TimeUnit.SECONDS); assertEquals("Exactly the allocated number of credits must be consumed", numWorkers * creditsPerWorker,count.get()); assertFalse(limiter.checkCredit(1)); }
public boolean checkCredit(double itemCost) { long cost = (long) (itemCost / creditsPerNanosecond); long credit; long currentDebit; long balance; do { currentDebit = debit.get(); credit = clock.currentNanoTicks(); balance = credit - currentDebit; if (balance > maxBalance) { balance = maxBalance; } balance -= cost; if (balance < 0) { return false; } } while (!debit.compareAndSet(currentDebit, credit - balance)); return true; }
RateLimiter { public boolean checkCredit(double itemCost) { long cost = (long) (itemCost / creditsPerNanosecond); long credit; long currentDebit; long balance; do { currentDebit = debit.get(); credit = clock.currentNanoTicks(); balance = credit - currentDebit; if (balance > maxBalance) { balance = maxBalance; } balance -= cost; if (balance < 0) { return false; } } while (!debit.compareAndSet(currentDebit, credit - balance)); return true; } }
RateLimiter { public boolean checkCredit(double itemCost) { long cost = (long) (itemCost / creditsPerNanosecond); long credit; long currentDebit; long balance; do { currentDebit = debit.get(); credit = clock.currentNanoTicks(); balance = credit - currentDebit; if (balance > maxBalance) { balance = maxBalance; } balance -= cost; if (balance < 0) { return false; } } while (!debit.compareAndSet(currentDebit, credit - balance)); return true; } RateLimiter(double creditsPerSecond, double maxBalance);  RateLimiter(double creditsPerSecond, double maxBalance, Clock clock); }
RateLimiter { public boolean checkCredit(double itemCost) { long cost = (long) (itemCost / creditsPerNanosecond); long credit; long currentDebit; long balance; do { currentDebit = debit.get(); credit = clock.currentNanoTicks(); balance = credit - currentDebit; if (balance > maxBalance) { balance = maxBalance; } balance -= cost; if (balance < 0) { return false; } } while (!debit.compareAndSet(currentDebit, credit - balance)); return true; } RateLimiter(double creditsPerSecond, double maxBalance);  RateLimiter(double creditsPerSecond, double maxBalance, Clock clock); boolean checkCredit(double itemCost); }
RateLimiter { public boolean checkCredit(double itemCost) { long cost = (long) (itemCost / creditsPerNanosecond); long credit; long currentDebit; long balance; do { currentDebit = debit.get(); credit = clock.currentNanoTicks(); balance = credit - currentDebit; if (balance > maxBalance) { balance = maxBalance; } balance -= cost; if (balance < 0) { return false; } } while (!debit.compareAndSet(currentDebit, credit - balance)); return true; } RateLimiter(double creditsPerSecond, double maxBalance);  RateLimiter(double creditsPerSecond, double maxBalance, Clock clock); boolean checkCredit(double itemCost);  }