Esiste qualche implementazione della coda di blocco che garantisce l'operazione fair take() se più utenti rimuovono l'elemento dalla stessa coda. Ho controllato LinkedBlockingQueue, LinkedTransferQueue e sembra che entrambi siano ingiusti. ArrayBlockingQueue fornisce operazioni corrette ma è limitato.C'è una coda di blocco corretto (non limitato) in java?
risposta
politica Equità può essere specificato per SynchronousQueue:
una coda costruito con equità impostato a veri concede le discussioni accesso a FIFO fine
Guardando il javadoc per quella classe mi fa ridere. Ad esempio clear non fa nulla – Woot4Moo
@ Woot4Moo tu chiaramente (il gioco di parole non intenzionale) non capisci come funziona quella classe - non ha alcuna capacità quindi non può essere cancellata. –
@Jed chiaramente non trovi l'umorismo nel documentare qualcosa che non fa nulla. – Woot4Moo
Siamo in grado di realizzare una sconfinata coda di blocco equa utilizzando una coda illimitata come coda ConcurrentLinked e un semaforo equo. La classe seguente non implementa tutti i metodi dall'interfaccia BlockingQueue ma solo alcuni di essi a scopo dimostrativo. Il metodo main() è scritto solo come test.
public class FairBlockingQueue<T> {
private final Queue<T> queue;
private final Semaphore takeSemaphore;
public FairBlockingQueue() {
queue = new ConcurrentLinkedQueue<T>();
takeSemaphore = new Semaphore(0, true);
}
public FairBlockingQueue(Collection<T> c) {
queue = new ConcurrentLinkedQueue<T>(c);
takeSemaphore = new Semaphore(c.size(), true);
}
public T poll() {
if (!takeSemaphore.tryAcquire()) {
return null;
}
return queue.poll();
}
public T poll(long millis) throws InterruptedException {
if (!takeSemaphore.tryAcquire(millis, TimeUnit.MILLISECONDS)) {
return null;
}
return queue.poll();
}
public T take() throws InterruptedException {
takeSemaphore.acquire();
return queue.poll();
}
public void add(T t) {
queue.add(t);
takeSemaphore.release();
}
public static void main(String[] args) throws Exception {
FairBlockingQueue<Object> q = new FairBlockingQueue<Object>();
Object o = q.poll();
assert o == null;
o = q.poll(1000);
assert o == null;
q.add(new Object());
q.add(new Object());
q.add(new Object());
o = q.take();
assert o != null;
o = q.poll();
assert o != null;
o = q.poll(1000);
assert o != null;
o = q.poll();
assert o == null;
}
}
soluzione bella ed equa, anche se suggerisco di usare PriorityBlockingQueue – Michael
Grazie, Michael. Se vogliamo utilizzare qualcosa di immediato, possiamo certamente optare per PriorityBlockingQueue, tuttavia il PBQ e l'FBQ suggerito sopra sono diversi per quanto riguarda l'ordinamento/l'ordinamento. PBQ mantiene i suoi elementi ordinati in base al loro ordinamento naturale utilizzando un heap prioritario, e prendendo gli elementi da un PBQ avviene in questo particolare ordine, mentre l'FBQ è supportato da un ConcurrentLinkedQueue che è una normale coda FIFO. –
BTW, il take() in PriorityBlockingQueue di Java SE 6 è corretto per i chiamanti poiché è implementato con un giusto ReentrantLock, ma in Java SE 7 è implementato con un ReentrantLock non corretto e rispettivamente non è più corretto per i chiamanti. Ho appena controllato le fonti. –
E su ConcurrentLinkedList? (Va bene, non è una "coda" per dire ... e non sono sicuro che sia più "giusto") –