Otros consejos

Esta pregunta merece una mejor respuesta.

El ConcurrentLinkedQueue de Java 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 planificador de la plataforma, como interrumpir un hilo, o si el hilo en cuestión es simplemente demasiado lento, otros hilos que compitan por el mismo recurso aún podrán Progreso. Si se trata de un bloqueo, por ejemplo, el hilo que lo sostiene podría interrumpirse y todos los hilos que esperan ese bloqueo se bloquearían. Los bloqueos intrínsecos (la palabra clave sincronizada ) en Java también pueden tener una penalización severa para el rendimiento, como cuando el bloqueo sesgado está involucrado y usted tiene contención, o después de que la VM decide" inflar " el bloqueo después de un período de gracia de giro y el bloqueo de subprocesos rivales ... es por eso que en muchos contextos (escenarios de contención baja / media), hacer comparaciones y conjuntos de referencias atómicas puede ser mucho más eficiente y esto es exactamente lo que muchos no -bloqueando estructuras de datos están haciendo.

El ConcurrentLinkedQueue de Java no solo no bloquea, sino que tiene la increíble 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á contención de la que hablar. En un escenario de productor múltiple / consumidor individual, el consumidor no competirá con los productores. Esta cola tiene contención cuando varios productores intentan offer () , pero eso es concurrencia por definición. Básicamente es un propósito general y una cola eficiente sin bloqueo.

En cuanto a que no es 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 un ConcurrentLinkedQueue en un escenario de consumidor / productor, simplemente cambie a abstracciones de nivel superior, como un buen marco de actor.

LinkedBlockingQueue bloquea al consumidor o al productor cuando la cola está vacía o llena y el subproceso de consumidor / productor respectivo se pone en suspensión. Pero esta característica de bloqueo tiene un costo: cada operación de poner o tomar es un bloqueo entre los productores o consumidores (si son muchos), por lo que en escenarios con muchos productores / consumidores la operación podría ser más lenta.

ConcurrentLinkedQueue no usa bloqueos, pero CAS , en sus operaciones de poner / tomar potencialmente reduciendo la contención con muchos hilos de productores y consumidores. Pero siendo un " espere gratis " estructura de datos, ConcurrentLinkedQueue no se bloqueará cuando esté vacío, lo que significa que el consumidor tendrá que lidiar con los valores take () que devuelven null en " ocupado esperando " ;, por ejemplo, con el hilo consumidor consumiendo CPU.

Entonces, ¿cuál es " mejor " depende de la cantidad 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 donde el ConcurrentLinkedQueue es claramente mejor es cuando los productores producen por primera vez algo y terminan su trabajo colocando el trabajo en la cola y solo después de que los consumidores comienzan consumir, sabiendo que se harán cuando la cola esté vacía. (aquí no hay concurrencia entre productor-consumidor, sino solo entre productor-productor y consumidor-consumidor)

Otra solución (que no escala bien) son los canales de encuentro: java.util.concurrent SynchronousQueue

Si su cola no es expandible y contiene solo un hilo productor / consumidor. Puede usar la cola sin bloqueo (no necesita bloquear el acceso a los datos).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top