2010-10-28 7 views
5

¿Existe alguna implementación de la cola de bloqueo que garantice la operación fair take() si varios consumidores están eliminando elementos de la misma cola? Comprobé LinkedBlockingQueue, LinkedTransferQueue y parece que ambos son injustos. ArrayBlockingQueue proporciona una operación justa pero limitada.¿Hay alguna cola de bloqueo de la feria (ilimitada) en java?

+2

¿Qué pasa con ConcurrentLinkedList? (De acuerdo, no es una 'cola' por decir ... y no estoy seguro si es más 'justo') –

Respuesta

0

política de imparcialidad se puede especificar para SynchronousQueue:

una cola construido con equidad establece a verdaderas subvenciones hilos de acceso en FIFO fin

+2

Al mirar el javadoc para esa clase me hace reír. Por ejemplo clear no hace nada – Woot4Moo

+1

@ Woot4Moo claramente (juego de palabras no intencionado) no entiendo cómo funciona esa clase - no tiene capacidad en absoluto por lo que no se puede borrar. –

+3

@Jed claramente no encuentras el humor al documentar algo que no hace nada. – Woot4Moo

3

Podemos implementar una ilimitada cola de bloqueo justo utilizando una cola ilimitada como la cola ConcurrentLinked y un semáforo justo. La siguiente clase no implementa todos los métodos desde la interfaz BlockingQueue, sino solo algunos con fines de demostración. El método main() se escribe solo como prueba.

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

buena y justa solución, aunque sugiero usar PriorityBlockingQueue – Michael

+0

Gracias, Michael. Si queremos usar algo de fábrica, sin duda podemos elegir un PriorityBlockingQueue, sin embargo, el PBQ y el FBQ sugerido anteriormente son diferentes en lo que respecta a ordenar/ordenar. PBQ mantiene sus elementos ordenados según su orden natural utilizando un montón de prioridad, y tomar elementos de un PBQ sucede en este orden particular, mientras que el FBQ está respaldado por una ConcurrentLinkedQueue que es una cola FIFO normal. –

+2

Por cierto, el take() en PriorityBlockingQueue de Java SE 6 es justo para los llamantes ya que se implementa con un ReentrantLock justo, pero en Java SE 7 se implementa con ReentrantLock no justo y, respectivamente, no es justo para quienes llaman. Acabo de consultar las fuentes. –

Cuestiones relacionadas