¿Cómo uso un ConcurrentLinkedQueue
en Java?
Usando esto LinkedQueue
, ¿debo preocuparme por la concurrencia en la cola? ¿O simplemente tengo que definir dos métodos (uno para recuperar elementos de la lista y otro para agregar elementos a la lista)?
Nota: obviamente, estos dos métodos deben estar sincronizados. ¿Correcto?
EDITAR: Lo que estoy tratando de hacer es esto: tengo una clase (en Java) con un método para recuperar elementos de la cola y otra clase con un método para agregar elementos a la cola. Los elementos agregados y recuperados de la lista son objetos de mi propia clase.
Una pregunta más: ¿necesito hacer esto en el método de eliminación?
while (queue.size() == 0){
wait();
queue.poll();
}
Solo tengo un consumidor y un productor.
java
concurrency
Ricardo Felgueiras
fuente
fuente
Respuestas:
No, no es necesario sincronizar los métodos y no es necesario definir ningún método; ya están en ConcurrentLinkedQueue, solo utilícelos. ConcurrentLinkedQueue realiza todas las operaciones de bloqueo y otras operaciones que necesita internamente; su (s) productor (es) agregan datos a la cola, y sus consumidores los sondean.
Primero, crea tu cola:
Ahora, donde sea que esté creando sus objetos de productor / consumidor, pase la cola para que tengan un lugar donde poner sus objetos (podría usar un establecedor para esto, pero prefiero hacer este tipo de cosas en un constructor):
y:
y agregarle cosas en su productor:
y sacar cosas en su consumidor (si la cola está vacía, poll () devolverá nulo, así que verifíquelo):
Para obtener más información, consulte el Javadoc
EDITAR:
Si necesita bloquear la espera de que la cola no esté vacía, probablemente desee utilizar un LinkedBlockingQueue y usar el método take (). Sin embargo, LinkedBlockingQueue tiene una capacidad máxima (el valor predeterminado es Integer.MAX_VALUE, que es más de dos mil millones) y, por lo tanto, puede o no ser apropiado según sus circunstancias.
Si solo tiene un hilo que pone cosas en la cola y otro hilo que saca cosas de la cola, ConcurrentLinkedQueue probablemente sea excesivo. Es más para cuando puede tener cientos o incluso miles de subprocesos accediendo a la cola al mismo tiempo. Es probable que sus necesidades se satisfagan utilizando:
Una ventaja de esto es que se bloquea en la instancia (cola), por lo que puede sincronizar en la cola para garantizar la atomicidad de las operaciones compuestas (como lo explicó Jared). NO PUEDE hacer esto con un ConcurrentLinkedQueue, ya que todas las operaciones se realizan SIN bloquear la instancia (usando variables java.util.concurrent.atomic). NO necesitará hacer esto si desea bloquear mientras la cola está vacía, porque poll () simplemente devolverá nulo mientras la cola está vacía, y poll () es atómico. Compruebe si poll () devuelve nulo. Si es así, espere () y vuelva a intentarlo. No es necesario bloquear.
Finalmente:
Honestamente, solo usaría un LinkedBlockingQueue. Todavía es excesivo para su aplicación, pero es probable que funcione bien. Si no tiene el rendimiento suficiente (¡PERFIL!), Siempre puede probar algo más, y significa que no tiene que lidiar con NINGÚN elemento sincronizado:
Todo lo demás es lo mismo. Put probablemente no se bloqueará, porque no es probable que coloque dos mil millones de objetos en la cola.
fuente
Collection.synchronizedList
devuelve unList
que no se implementaQueue
.ConcurrentLinkedQueue
para Producer Consumer una buena idea, me refiero a esta publicación stackoverflow.com/questions/1426754/…Esto es en gran parte un duplicado de otra pregunta. .
Aquí está la sección de esa respuesta que es relevante para esta pregunta:
¿Necesito hacer mi propia sincronización si uso java.util.ConcurrentLinkedQueue?
Las operaciones atómicas en las colecciones concurrentes se sincronizan automáticamente. En otras palabras, cada llamada individual a la cola está garantizada como segura para subprocesos sin ninguna acción de su parte. Lo que no se garantiza que sea seguro para subprocesos son las operaciones que realice en la colección que no sean atómicas.
Por ejemplo, esto es seguro para subprocesos sin ninguna acción de su parte:
o
Sin embargo; Las llamadas no atómicas a la cola no son automáticamente seguras para subprocesos. Por ejemplo, las siguientes operaciones no son seguras para subprocesos automáticamente:
Este último no es seguro para subprocesos, ya que es muy posible que entre el momento en que se llama a isEmpty y el momento en que se llama a la encuesta, otros subprocesos hayan agregado o eliminado elementos de la cola. La forma segura de realizar esto es así:
Nuevamente ... las llamadas atómicas a la cola son automáticamente seguras para subprocesos. Las llamadas no atómicas no lo son.
fuente
Use poll para obtener el primer elemento y agregue para agregar un nuevo último elemento. Eso es todo, sin sincronización ni nada más.
fuente
Esto es probablemente lo que está buscando en términos de seguridad de subprocesos y "belleza" cuando intenta consumir todo en la cola:
Esto garantizará que salga cuando la cola esté vacía y que continúe sacando objetos de ella siempre que no esté vacía.
fuente
ConcurentLinkedQueue es una implementación sin espera / bloqueo muy eficiente (consulte el javadoc como referencia), por lo que no solo no necesita sincronizar, sino que la cola no bloqueará nada, por lo que es virtualmente tan rápido como un no sincronizado (no hilo seguro) uno.
fuente
Úselo como lo haría con una colección no concurrente. Las clases Concurrent [Collection] envuelven las colecciones regulares para que no tenga que pensar en sincronizar el acceso.
Editar: ConcurrentLinkedList no es en realidad solo un contenedor, sino una mejor implementación concurrente. De cualquier manera, no tiene que preocuparse por la sincronización.
fuente