De los JavaDocs:
- Un ConcurrentLinkedQueue es una opción apropiada cuando muchos hilos compartirán el acceso a una colección común. Esta cola no permite elementos nulos.
- ArrayBlockingQueue es un clásico "búfer acotado", en el que una matriz de tamaño fijo contiene elementos insertados por productores y extraídos por los consumidores. Esta clase admite una política de equidad opcional para ordenar hilos de productores y consumidores en espera
- LinkedBlockingQueue generalmente tiene un mayor rendimiento que las colas basadas en matrices, pero un rendimiento menos predecible en la mayoría de las aplicaciones concurrentes.
Tengo 2 escenarios, uno requiere la cola para apoyar a muchos productores (hilos que lo usan) con un consumidor y el otro es al revés.
No entiendo qué implementación usar. ¿Alguien puede explicar cuáles son las diferencias?
Además, ¿cuál es la "política de equidad opcional" en el ArrayBlockingQueue
?
java
multithreading
concurrency
queue
David Hofmann
fuente
fuente
Respuestas:
Básicamente, la diferencia entre ellos son las características de rendimiento y el comportamiento de bloqueo.
Tomando el más fácil primero,
ArrayBlockingQueue
es una cola de un tamaño fijo. Entonces, si establece el tamaño en 10 e intenta insertar un undécimo elemento, la instrucción de inserción se bloqueará hasta que otro hilo elimine un elemento. El problema de la equidad es qué sucede si varios subprocesos intentan insertarse y eliminarse al mismo tiempo (en otras palabras, durante el período en que se bloqueó la Cola). Un algoritmo de equidad asegura que el primer hilo que pregunta es el primer hilo que recibe. De lo contrario, un subproceso dado puede esperar más que otros subprocesos, lo que provoca un comportamiento impredecible (a veces un subproceso solo tomará varios segundos porque otros subprocesos que comenzaron más tarde se procesaron primero). La desventaja es que se necesitan gastos generales para gestionar la equidad, lo que ralentiza el rendimiento.La diferencia más importante entre
LinkedBlockingQueue
yConcurrentLinkedQueue
es que si solicita un elemento de aLinkedBlockingQueue
y la cola está vacía, su hilo esperará hasta que haya algo allí. AConcurrentLinkedQueue
regresará de inmediato con el comportamiento de una cola vacía.Cuál depende de si necesita el bloqueo. Cuando tienes muchos productores y un consumidor, parece que sí. Por otro lado, donde tiene muchos consumidores y solo un productor, es posible que no necesite el comportamiento de bloqueo y puede estar feliz de que los consumidores verifiquen si la cola está vacía y continúen si es así.
fuente
ConcurrentLinkedQueue significa que no se toman bloqueos (es decir, no hay llamadas sincronizadas (esto) o Lock.lock ). Utilizará una operación CAS - Compare and Swap durante las modificaciones para ver si el nodo head / tail sigue siendo el mismo que cuando comenzó. Si es así, la operación tiene éxito. Si el nodo cabeza / cola es diferente, girará e intentará nuevamente.
LinkedBlockingQueue se bloqueará antes de cualquier modificación. Por lo tanto, sus llamadas de oferta se bloquearían hasta que obtengan el bloqueo. Puede usar la sobrecarga de la oferta que requiere una unidad de tiempo para decir que solo está dispuesto a esperar X cantidad de tiempo antes de abandonar el complemento (generalmente es bueno para las colas de tipo de mensaje donde el mensaje está obsoleto después de X número de milisegundos).
La equidad significa que la implementación de bloqueo mantendrá los hilos ordenados. Es decir, si el hilo A entra y luego el hilo B entra, el hilo A obtendrá primero el bloqueo. Sin equidad, no está definido realmente qué sucede. Lo más probable es que sea el próximo hilo que se programe.
En cuanto a cuál usar, depende. Tiendo a usar ConcurrentLinkedQueue porque el tiempo que les toma a mis productores obtener trabajo para poner en la cola es diverso. No tengo muchos productores produciendo en el mismo momento. Pero el lado del consumidor es más complicado porque la encuesta no entrará en un buen estado de reposo. Tienes que manejar eso tú mismo.
fuente
El título de su pregunta menciona el bloqueo de colas. Sin embargo, no
ConcurrentLinkedQueue
es una cola de bloqueo.Los
BlockingQueue
s sonArrayBlockingQueue
,DelayQueue
,LinkedBlockingDeque
,LinkedBlockingQueue
,PriorityBlockingQueue
, ySynchronousQueue
.Algunos de estos no son claramente ajuste para su propósito (
DelayQueue
,PriorityBlockingQueue
ySynchronousQueue
).LinkedBlockingQueue
yLinkedBlockingDeque
son idénticos, excepto que este último es una Cola de doble extremo (implementa la interfaz Deque).Como
ArrayBlockingQueue
solo es útil si desea limitar la cantidad de elementos, me quedaría con ellosLinkedBlockingQueue
.fuente
ArrayBlockingQueue tiene una menor huella de memoria, puede reutilizar el nodo del elemento, no como LinkedBlockingQueue que tiene que crear un objeto LinkedBlockingQueue $ Node para cada nueva inserción.
fuente
ArrayBlockingQueue
tendrá una huella de memoria mucho peor: todavía tiene una gran matriz asignada en la memoria todo el tiempo, mientras que elLinkedBlockingQueue
tendrá un consumo de memoria insignificante cuando cerca de vacío.SynchronousQueue
(Tomado de otra pregunta )SynchronousQueue
es más un traspaso, mientras que elLinkedBlockingQueue
solo permite un solo elemento. La diferencia es que laput()
llamada a aSynchronousQueue
no volverá hasta que haya unatake()
llamada correspondiente , pero con unLinkedBlockingQueue
tamaño de 1, laput()
llamada (a una cola vacía) volverá inmediatamente. Es esencialmente laBlockingQueue
implementación para cuando realmente no quieres una cola (no quieres mantener ningún dato pendiente).LinkedBlockingQueue
(LinkedList
Implementación pero no exactamente JDK Implementación deLinkedList
Utiliza un nodo de clase interna estático para mantener enlaces entre elementos)Constructor para LinkedBlockingQueue
Clase de nodo utilizada para mantener enlaces
3) ArrayBlockingQueue (Implementación de matriz)
Constructor para ArrayBlockingQueue
En mi humilde opinión, la diferencia más grande entre
ArrayBlockingQueue
yLinkedBlockingQueue
está clara desde el constructor uno tiene la estructura de datos subyacente Array y otra lista enlazada .ArrayBlockingQueue
utiliza el algoritmo de doble condición de bloqueo único yLinkedBlockingQueue
es una variante del algoritmo de "cola de dos bloqueos" y tiene 2 bloqueos y 2 condiciones (takeLock, putLock)fuente
ConcurrentLinkedQueue no tiene bloqueo, LinkedBlockingQueue no lo es. Cada vez que invocas LinkedBlockingQueue.put () o LinkedBlockingQueue.take (), primero debes adquirir el bloqueo. En otras palabras, LinkedBlockingQueue tiene poca concurrencia. Si le importa el rendimiento, pruebe ConcurrentLinkedQueue + LockSupport.
fuente