SmoothBursty
主要思想
記錄 1秒內的微秒數/permitsPerSencond = 時間間隔interval,每一個interval可獲得一個令牌
根據允許使用多少秒內的令牌參數,計算出maxPermits
setRate時初始化下次interval時間,及storedPermits
acquire時,計算當前nowMicros,如果大於下次interval時間時間,則更新storedPermits和下次interval時間,計算storedPermits能否滿足此次acquire,如果能,則需要等待的時間為0,如果不能,則計算還需要多少微秒等待,並在非同步塊外執行sleep操作
如果其他線程已經刷新了nextFreeTicketMicros,會如下情況acquire是無timeout的
Thread 1: acquire 11 -> storedPermits不能滿足要求 -> waitTime = (acquire - stored) * stableIntervalMicros -> nextFreeTicketMicros += waitMicros -----> out lock sleep
Thread 2: acquire 2 -> nowMicros < nextFreeTicketMicros , stored = 0,被線程1消耗完了 -> freshPermits = requiredPermits - storedPermitsToSpend 即 = requiredPermits -> waitTime = freshPermits * stableIntervalMicros
-> nextFreeTicketMicros += waitTime,此時的nextFreeTicketMicros包含了Thread1需要等待的時間 -------> out lock sleep a longer time
tryAquire(num,timeout)邏輯
timeoutMicros = timeout.toMicros
lock()
nowMicros = ...
canAcquire = nextFreeTicketMicros <= nowMicros + timeoutMicros
if(!canAcquire){
return false;
}
else{
microsToWait = ...
}
unlock()
sleep(microsToWait)
return true;
SmoothWarmingUp
主要思想和SmoothBursty相似,由於帶預熱過程,剛開始由於availablePermitsAboveThreshold>0.0,速率會較慢,如果持續獲取令牌,則會使availablePermitsAboveThreshold=0,速率變快
-
從0->thresholdPermits,生成一個令牌的時間:stableIntervalMicros
-
從thresholdPermits-> maxPermits ,生成一個令牌的時間:stableIntervalMicros + permits * slope;
@Override
final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {
resync(nowMicros);
long returnValue = nextFreeTicketMicros;
//當前需要且盡最大可能消費的
double storedPermitsToSpend = min(requiredPermits, this.storedPermits);
//新鮮permits個數,這些個數是一定會產生等待的,除了0
double freshPermits = requiredPermits - storedPermitsToSpend;
//計算需要wait的總時間
long waitMicros =
//非busty類型的storedPermitsToWaitTime直接返回0
storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
+ (long) (freshPermits * stableIntervalMicros);
//下次有票時間
this.nextFreeTicketMicros = LongMath.saturatedAdd(nextFreeTicketMicros, waitMicros);
this.storedPermits -= storedPermitsToSpend;
return returnValue;
}//已知permitsToTake <= storedPermits @Override long storedPermitsToWaitTime(double storedPermits, double permitsToTake) { //減去預熱需要保留的permits,剩下的可消耗的數量 double availablePermitsAboveThreshold = storedPermits - thresholdPermits; long micros = 0; // measuring the integral on the right part of the function (the climbing line) //如果有剩余可用的令牌 if (availablePermitsAboveThreshold > 0.0) { //剩余可用的和需要獲取的個數取小值 double permitsAboveThresholdToTake = min(availablePermitsAboveThreshold, permitsToTake); // TODO(cpovirk): Figure out a good name for this variable. //用可消耗的數量 + (可消耗的數量 - 實際消耗的數量)permitsToTime //在預熱階段從thresholdPermits到maxPermits的耗時並非是stableIntervalMicros * n //會耗費更多的時間,其計算規則不同,所以才需要把permitsAboveThresholdToTake從permitsToTake減去 //length 可能作為一個經驗值,相當於補充permitsAboveThresholdToTake個令牌需要的平均時間值*2 //剩余可用的-實際需要且最大能消耗的令牌,得到最終剩余的令牌個數,可能是0 double length = permitsToTime(availablePermitsAboveThreshold) + permitsToTime(availablePermitsAboveThreshold - permitsAboveThresholdToTake); //這里確實不好理解,從語義環境來說,它是從 thresholdPermits 到 maxPertmis 過程中 //生成 permitsAboveThresholdToTake 個令牌需要耗費的時間 //並且帶coldFactor的構造函數不是public,SmoothWarmingUp也是private-package的 micros = (long) (permitsAboveThresholdToTake * length / 2.0); //從permitsToTake中減去保留預熱需留下個數后最終消耗的個數,這部分個數由於是提前存在的、富余的 //因此不需要計算到wait時間 permitsToTake -= permitsAboveThresholdToTake; } // measuring the integral on the left part of the function (the horizontal line) //如果沒有剩余可用令牌,走的是stableIntervalMicros * n micros += (stableIntervalMicros * permitsToTake); return micros; }
length/2可以理解為下圖
//permits值越小,需要的時間就越少,值越大,需要的時間就越大
private double permitsToTime(double permits) {
//double coldIntervalMicros = stableIntervalMicros * coldFactor;
// thresholdPermits = 0.5 * warmupPeriodMicros / stableIntervalMicros;
//maxPermits =
thresholdPermits + 2.0 * warmupPeriodMicros / (stableIntervalMicros + coldIntervalMicros);
//slope帶比率的時間,可以理解為增長因子
//slope = (coldIntervalMicros - stableIntervalMicros) / (maxPermits - thresholdPermits)
//return表示成這樣更易於理解 stableIntervalMicros + (coldIntervalMicros - stableIntervalMicros) * (permits/(maxPermits - thresholdPermits))
return stableIntervalMicros + permits * slope;
}