2010-07-26 14 views
6

Tengo 3 hilos: 2 consumidores, ConsumerA y ConsumerB, y Producer.Java: ¿LinkedBlockingQueue tiene en cuenta el orden de los consumidores?

I también tienen una LinkedBlockingQueue queue

En t = 1: ConsumerA llamadas queue.take()

En t = 2: Consumer B pide queue.take()

En t = 3 : Producer llamadas queue.put (foo)

¿Está garantizado que ConsumerA reciba foo antes que ConsumerB? En otras palabras, ¿el orden en el que los consumidores invocan take() es el orden en que se notifica a cada uno?

En caso negativo, ¿existe una estructura de datos alternativa que otorgará mayor prioridad en función del pedido?

Respuesta

3

Al mirar el código fuente, no está garantizado. Hay un mecanismo de bloque protegido en su lugar con el despertar de un hilo al azar, dependiendo de cómo se sienta el programador.

notEmpty.signal(); // propagate to a non-interrupted thread 

código completa: http://kickjava.com/src/java/util/concurrent/LinkedBlockingQueue.java.htm

Editar: sólo se veía de nuevo en ReenterantLock y Condiciones, los hilos se señalizan en orden FIFO, al parecer. Por lo tanto, primero se señalará el primer hilo para esperar a la inserción. Sin embargo, estos son detalles de implementación! No confíes en ellos.

no se requiere una implementación a definir exactamente las mismas garantías o semántica para las tres formas de de espera, ni se requiere para apoyar interrupción de la suspensión real de la rosca

3

En muchos casos, el orden de los hilos que entran en la cola estará en el orden apropiado. Sin embargo, la cola LinkedBlocking utiliza un bloqueo injusto. Lo que hace es permitir que los hilos se inmiscuyan entre sí. Aunque es raro, lo siguiente podría suceder.

  • Thread A entra y vota.
  • Tema B entra intentos para la encuesta - Tema A mantiene el bloqueo y parques hilo B.
  • acabados Tema señales A y B
  • Tema C entra y adquiere la cerradura antes de que B no aparcado en
  • completamente
  • intentos Tema B sondear - El hilo C sostiene el bloqueo y estaciona el hilo B.

Esta es una posibilidad.

1

Así que cavar a través de las entrañas de la fuente de Java 6 (omitir la parte entre las normas horizontales si no se preocupan por encontrar el código actual responsable de estas cosas)


La clase java.util.concurrent.LinkedBlockingQueue implementa usando mutex instancias de java.util.concurrent.locks.ReentrantLock.

A su vez, las variables de sincronización se generan usando java.util.concurrent.locks.ReentrantLock.newCondition() que llama a java.util.concurrent.locks.ReentrantLock$Sync.newCondition().

El método java.util.concurrent.locks.ReentrantLock$Sync.newCondition() devuelve una instancia de java.util.concurrent.AbstractQueuedSynchronizer$ConditionObject que implementa las llamadas normales variables de sincronización a await(), signal() y signalAll() descritos por la interfaz java.util.concurrent.locks.Condiion.


Mirando el código fuente de la clase ConditionObject, mantiene dos miembros llamados firstWaiter y lastWaiter que son los primeros y últimos nodos en una cola de bloqueo CLH (instancias de java.util.concurrent.locks.AbstractQueuedSynchronizer$Node).

La documentación en la que los estados de clase:

Un hilo puede tratar de adquirir si es primero en la cola. Pero ser el primero no garantiza el éxito; solo da derecho a contender. Por lo tanto, es probable que el hilo contendiente lanzado actualmente deba volver a esperar.

Así que creo que la respuesta es que el método take() en LinkedBlockingQueue intentos de dar un trato preferencial a aquellos hilo que llama take() anterior. Le dará al primer hilo para llamar al take() la primera oportunidad de agarrar un artículo de la cola cuando esté disponible, pero debido a tiempos de espera, interrupciones, etc. que el hilo no se garantiza ser el primer hilo para sacar el elemento de la cola.

Tenga en cuenta que esto es completamente específico para esta implementación en particular. En general, debe suponer que las llamadas al take() activarán un hilo de espera aleatorio cuando un elemento de la cola esté disponible y no necesariamente el primero que llamó al take().

Cuestiones relacionadas