Mi pregunta se relaciona con esta pregunta formulada anteriormente. En situaciones en las que estoy usando una cola para la comunicación entre los hilos del productor y del consumidor, ¿la gente generalmente recomendaría usar LinkedBlockingQueue
o ConcurrentLinkedQueue
?
¿Cuáles son las ventajas / desventajas de usar uno sobre el otro?
La principal diferencia que puedo ver desde la perspectiva de la API es que a LinkedBlockingQueue
se puede limitar opcionalmente.
ConcurrentLinkedQueue
también es útil si su hilo está comprobando varias colas. Por ejemplo, en un servidor multiinquilino. Suponiendo que, por razones de aislamiento, no utilice una sola cola de bloqueo y un discriminador de inquilinos en su lugar.take()
yput()
simplemente consume recursos adicionales (términos de sincronización) queConcurrentLinkedQueue
. aunque es el caso de usar colas limitadas para escenarios de Productor-consumidorEsta pregunta merece una mejor respuesta.
Java
ConcurrentLinkedQueue
se basa en el famoso algoritmo de Maged M. Michael y Michael L. Scott para colas sin bloqueo sin bloqueo ."Sin bloqueo" como término aquí para un recurso en disputa (nuestra cola) significa que independientemente de lo que haga el programador de la plataforma, como interrumpir un hilo, o si el hilo en cuestión es simplemente demasiado lento, otros hilos compiten por el mismo recurso todavía podrá progresar. Si hay un bloqueo involucrado, por ejemplo, el hilo que sostiene el bloqueo podría interrumpirse y todos los hilos que esperan ese bloqueo se bloquearían. Los bloqueos intrínsecos (la
synchronized
palabra clave) en Java también pueden tener una penalización severa para el rendimiento, como cuando el bloqueo sesgadoestá involucrado y tiene contención, o después de que la máquina virtual decida "inflar" el bloqueo después de un período de gracia de giro y bloquear los subprocesos en conflicto ... por lo que en muchos contextos (escenarios de contención baja / media), comparar y Los conjuntos de referencias atómicas pueden ser mucho más eficientes y esto es exactamente lo que están haciendo muchas estructuras de datos sin bloqueo.Java
ConcurrentLinkedQueue
no solo no bloquea, sino que tiene la asombrosa propiedad de que el productor no compite con el consumidor. En un escenario de productor único / consumidor único (SPSC), esto realmente significa que no habrá disputas de las que hablar. En un escenario de productor múltiple / consumidor único, el consumidor no competirá con los productores. Esta cola tiene contención cuando varios productores lo intentanoffer()
, pero eso es concurrencia por definición. Es básicamente una cola sin bloqueos de propósito general y eficiente.En cuanto a que no sea un
BlockingQueue
, bueno, bloquear un hilo para esperar en una cola es una forma terriblemente terrible de diseñar sistemas concurrentes. No lo hagas. Si no puede descubrir cómo usar unConcurrentLinkedQueue
en un escenario de consumidor / productor, simplemente cambie a abstracciones de nivel superior, como un buen marco de actor.fuente
LinkedBlockingQueue
bloquea al consumidor o al productor cuando la cola está vacía o llena y el hilo consumidor / productor respectivo se pone en suspensión. Pero esta característica de bloqueo tiene un costo: cada operación de compra o venta se bloquea entre los productores o consumidores (si es que hay muchos), por lo que en escenarios con muchos productores / consumidores la operación puede ser más lenta.ConcurrentLinkedQueue
no está usando bloqueos, sino CAS , en sus operaciones de venta / adquisición, lo que potencialmente reduce la contención con muchos hilos de productores y consumidores. Pero al ser una estructura de datos "sin esperar",ConcurrentLinkedQueue
no se bloqueará cuando esté vacía, lo que significa que el consumidor tendrá que lidiar con los valorestake()
devueltosnull
"esperando ocupado", por ejemplo, con el hilo del consumidor consumiendo CPU.Entonces, cuál es "mejor" depende del número de hilos de consumo, de la tasa que consumen / producen, etc. Se necesita un punto de referencia para cada escenario.
Un caso de uso particular en el
ConcurrentLinkedQueue
que claramente es mejor es cuando los productores primero producen algo y terminan su trabajo colocando el trabajo en la cola y solo después de que los consumidores comienzan a consumir, sabiendo que terminarán cuando la cola esté vacía. (aquí no hay concurrencia entre productor-consumidor sino solo entre productor-productor y consumidor-consumidor)fuente
unbounded blockingqueue
se usa, sería mejor que el concurrente basado en CASConcurrentLinkedQueue
Otra solución (que no escala bien) son los canales de encuentro: java.util.concurrent SynchronousQueue
fuente
Si su cola no es expandible y contiene solo un hilo productor / consumidor. Puede utilizar la cola sin bloqueo (no es necesario bloquear el acceso a los datos).
fuente