Esto depende de la aplicación.
Imagínese el caso en el que varios subprocesos quieren un token para hacer un poco de acción a nivel mundial de la velocidad limitada a ninguna ráfaga permitido (es decir, que desea limitar a 10 acciones por cada 10 segundos, pero no desea que 10 acciones que sucedan en el primer segundo y luego permanecer 9 segundos detenidos).
El DelayedQueue tiene una desventaja: el orden en el que los subprocesos solicitan tokens podría no ser el orden en el que reciben su solicitud. Si se bloquean varios subprocesos esperando un token, no está claro cuál tomará el siguiente token disponible. Incluso podría tener hilos esperando para siempre, en mi punto de vista.
Una solución es tener un intervalo de tiempo mínimo entre dos acciones consecutivas y tomar acciones en el mismo orden en que se solicitaron.
Aquí hay una implementación:
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);
}
}
}