2010-10-28 12 views
5

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?

+2

E su ConcurrentLinkedList? (Va bene, non è una "coda" per dire ... e non sono sicuro che sia più "giusto") –

risposta

0

politica Equità può essere specificato per SynchronousQueue:

una coda costruito con equità impostato a veri concede le discussioni accesso a FIFO fine

+2

Guardando il javadoc per quella classe mi fa ridere. Ad esempio clear non fa nulla – Woot4Moo

+1

@ Woot4Moo tu chiaramente (il gioco di parole non intenzionale) non capisci come funziona quella classe - non ha alcuna capacità quindi non può essere cancellata. –

+3

@Jed chiaramente non trovi l'umorismo nel documentare qualcosa che non fa nulla. – Woot4Moo

3

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; 
    } 
} 
+0

soluzione bella ed equa, anche se suggerisco di usare PriorityBlockingQueue – Michael

+0

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. –

+2

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. –

Problemi correlati