Это зависит от приложения.
Представьте себе случай, когда несколько потоков хотят, чтобы токен выполнял какое-либо глобально ограниченное по скорости действие, при котором пакет не был разрешен (т.е. вы хотите ограничить 10 действий в 10 секунд, но вы не хотите, чтобы 10 действий происходили в первую секунду, а затем оставались 9 секунд остановились).
Недостаток DelayedQueue: порядок, в котором потоки запрашивают токены, может не совпадать с порядком, в котором они получают свой запрос. Если несколько потоков заблокированы в ожидании токена, неясно, какой из них возьмет следующий доступный токен. С моей точки зрения, у вас могут быть темы, ожидающие вечно.
Одним из решений является минимальный интервал времени между двумя последовательными действиями и выполнение действий в том же порядке, в котором они были запрошены.
Вот реализация:
public class LeakyBucket {
protected float maxRate;
protected long minTime;
//holds time of last action (past or future!)
protected long lastSchedAction = System.currentTimeMillis();
public LeakyBucket(float maxRate) throws Exception {
if(maxRate <= 0.0f) {
throw new Exception("Invalid rate");
}
this.maxRate = maxRate;
this.minTime = (long)(1000.0f / maxRate);
}
public void consume() throws InterruptedException {
long curTime = System.currentTimeMillis();
long timeLeft;
//calculate when can we do the action
synchronized(this) {
timeLeft = lastSchedAction + minTime - curTime;
if(timeLeft > 0) {
lastSchedAction += minTime;
}
else {
lastSchedAction = curTime;
}
}
//If needed, wait for our time
if(timeLeft <= 0) {
return;
}
else {
Thread.sleep(timeLeft);
}
}
}