Isso depende da aplicação.
Imagine o caso em que vários encadeamentos desejam que um token realize alguma ação com taxa global limitada, sem permissão permitida (ou seja, você deseja limitar 10 ações por 10 segundos, mas não deseja que 10 ações aconteçam no primeiro segundo e permaneça 9 segundos parados).
O DelayedQueue tem uma desvantagem: a ordem na qual os tokens de solicitação de threads podem não ser a ordem em que eles recebem sua solicitação. Se vários threads estiverem bloqueados aguardando um token, não está claro qual deles utilizará o próximo token disponível. Você pode até ter tópicos esperando para sempre, no meu ponto de vista.
Uma solução é ter um intervalo mínimo de tempo entre duas ações consecutivas e executar ações na mesma ordem em que foram solicitadas.
Aqui está uma implementação:
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);
}
}
}