我寫了一個簡單的速率限制器,用于限制遠程服務的使用:
我寫了一個簡單的速率限制器,用于限制遠程服務的使用。
import java.util.concurrent.Executors。
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Semaphore。
import java.util.concurrent.TimeUnit;
class SimpleRateLimiter {
private Semaphore semaphore。
private int maxPermits;
private TimeUnit timePeriod;
private ScheduledExecutorService調度器。
public static SimpleRateLimiter create(int permits, TimeUnit timePeriod) /span>{
SimpleRateLimiter limiter = new SimpleRateLimiter(許可證,timePeriod)。
limiter.schedulePermitReplenishment()。
return limiter。
}
private SimpleRateLimiter(int permits, TimeUnit timePeriod) /span> {
this.semaphore = new Semaphore(許可證)。
this.maxPermits = permits;
this.timePeriod = timePeriod;
}
public boolean tryAcquire() {
return semaphore.tryAcquire()。
}
public void blockAcquire() throws InterruptedException {
semaphore.acquisition()。
}
public void stop() {
scheduler.shutdownNow()。
semaphore.drainPermits()。
}
public int getPermitCount() {
return semaphore.availablePermits()。
}
public void schedulePermitReplenishment() {
scheduler = Executors.newScheduledThreadPool(1)。
scheduler.scheduleWithFixedDelay(() -> {
semaphore.release(maxPermits - semaphore.availablePermits())。
}, 0, 1, timePeriod)。)
}
而要使用它,我有以下的方法:
SimpleRateLimiter rateLimiter = SimpleRateLimiter. create(100, TimeUnit.SECONDS)。
...
//在一些執行緒回圈中:。
if (rateLimiter.tryAcquire() ) {
System.out.println("Permit left: " rateLimiter.getPermitCount())。
...
}
一切都很好,直到在一個正常的日子里它停止作業。檢查日志,我發現rateLimiter.getPermitCount()達到了104,(我懷疑)這使得maxPermits - semaphore.availablePermits()變成了負數并拋出了Exception,導致schedulePermitReplenishment()里面的單執行緒調度器停止作業。我的問題是,在什么情況下getPermitCount()可以超過100,因為semaphore只能被內部訪問,而且只能被單執行緒訪問?
謝謝你
uj5u.com熱心網友回復:
你的代碼有幾個問題。但其中一個問題是schedulePermitReplenishment方法中潛在的競賽條件。
如果這個方法被同時呼叫,并且你將有例如9個可用的許可證和10個最大的許可證,那么你可能會出現以下情況:
semaphore.release.com
semaphore.release(10 - 9);
這與sempahore.release(1)相同。因此,如果2個執行緒同時呼叫這個,你最終會得到11個許可證,而不是10個。
而且正如你已經指出的,在下一次呼叫 schedulePermitReplenishment 時,你將會有一個 10-11=-1 的許可被釋放,你最終會出現一個例外(這確實被執行者吞噬了)。
為什么你需要補充許可證?票據是否丟失了?因為這可能是導致可用票數大于 "最大 "票數的另一個原因。例如,如果有一張票被拿走了,你會呼叫補充,而該票最終被退回,你也會有太多的票。
我不太確定這段代碼將如何使用,但你也可以在執行者欄位上進行資料競賽。也許在構造器中創建執行器而不是替換它是更好的做法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/308328.html
標籤:
