Pregunta

¿Cómo uso un ConcurrentLinkedQueue en Java?
Al usar este 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 tienen que estar sincronizados. Derecho?


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();
}

Sólo tengo un consumidor y un productor.

¿Fue útil?

Solución

No, no es necesario que los métodos estén sincronizados, y usted no necesita definir ningún método; ya están en ConcurrentLinkedQueue, solo úsalos. ConcurrentLinkedQueue realiza todas las operaciones de bloqueo y de otro tipo que necesita internamente; su (s) productor (es) agrega (s) datos a la cola, y sus consumidores la buscan.

Primero, crea tu cola:

Queue<YourObject> queue = new ConcurrentLinkedQueue<YourObject>();

Ahora, donde sea que esté creando sus objetos de productor / consumidor, pase la cola para que tengan un lugar donde colocar sus objetos (podría usar un setter para esto, pero prefiero hacer este tipo de cosas en un constructor ):

YourProducer producer = new YourProducer(queue);

y:

YourConsumer consumer = new YourConsumer(queue);

y agrégale cosas a tu productor:

queue.offer(myObject);

y elimine cosas en su consumidor (si la cola está vacía, poll () devolverá el valor nulo, así que verifíquelo):

YourObject myObject = queue.poll();

Para obtener más información, consulte el Javadoc

EDITAR:

Si necesita bloquear la espera para que la cola no esté vacía, probablemente desee usar un LinkedBlockingQueue , y use el método take (). Sin embargo, LinkedBlockingQueue tiene una capacidad máxima (por defecto es Integer.MAX_VALUE, que es más de dos mil millones) y, por lo tanto, puede o no ser apropiado dependiendo de sus circunstancias.

Si solo tienes un hilo que pone cosas en la cola, y otro hilo que saca cosas de la cola, es probable que ConcurrentLinkedQueue sea excesivo. Es más cuando hay cientos o incluso miles de subprocesos que acceden a la cola al mismo tiempo. Sus necesidades probablemente serán satisfechas mediante el uso de:

Queue<YourObject> queue = Collections.synchronizedList(new LinkedList<YourObject>());

Una ventaja adicional de esto es que se bloquea en la instancia (cola), por lo que puede sincronizar en la cola para asegurar la atomicidad de las operaciones compuestas (como lo explica Jared). NO PUEDE hacer esto con un ConcurrentLinkedQueue, ya que todas las operaciones se realizan SIN bloquear la instancia (utilizando las variables java.util.concurrent.atomic). NO tendrá que hacer esto si desea bloquear mientras la cola está vacía, porque poll () simplemente devolverá el valor nulo mientras la cola esté vacía, y poll () es atómico. Compruebe si poll () devuelve un valor nulo. Si lo hace, espere (), luego intente nuevamente. No es necesario bloquear.

Finalmente:

Honestamente, solo uso LinkedBlockingQueue. Todavía es una exageración para su aplicación, pero es probable que funcione bien. Si no tiene el suficiente rendimiento (¡PERFIL!), Siempre puedes intentar algo más, y significa que no tienes que lidiar con NINGUNA cosa sincronizada:

BlockingQueue<YourObject> queue = new LinkedBlockingQueue<YourObject>();

queue.put(myObject); // Blocks until queue isn't full.

YourObject myObject = queue.take(); // Blocks until queue isn't empty.

Todo lo demás es igual. Poner probablemente no se bloqueará, porque no es probable que pongas dos mil millones de objetos en la cola.

Otros consejos

Esto es en gran parte un duplicado de otra pregunta .

Aquí está la sección de esa respuesta que es relevante para esta pregunta:

¿Debo hacer mi propia sincronización si uso java.util.ConcurrentLinkedQueue?

Las operaciones atómicas en las colecciones concurrentes se sincronizan para usted. En otras palabras, se garantiza que cada llamada individual a la cola es segura para subprocesos sin ninguna acción de su parte. Lo que no tiene seguro de subprocesos son las operaciones que realiza en la colección que no son atómicas.

Por ejemplo, esto es seguro para hebras sin ninguna acción de su parte:

queue.add(obj);

o

queue.poll(obj);

Sin embargo; Las llamadas no atómicas a la cola no son automáticamente seguras para subprocesos. Por ejemplo, las siguientes operaciones son no automáticamente seguras para hilos:

if(!queue.isEmpty()) {
   queue.poll(obj);
}

Este último no es seguro para subprocesos, ya que es muy posible que, entre el momento en que se llama isEmpty y el llamado a la encuesta de tiempo, otros subprocesos hayan agregado o eliminado elementos de la cola. La manera segura de hacerlo es así:

synchronized(queue) {
    if(!queue.isEmpty()) {
       queue.poll(obj);
    }
}

Nuevamente ... las llamadas atómicas a la cola son automáticamente seguras para subprocesos. Las llamadas no atómicas no lo son.

Use encuesta para obtener el primer elemento, y agregar para agregar un último elemento nuevo. Eso es todo, no hay sincronización ni nada más.

Esto es probablemente lo que está buscando en términos de seguridad de subprocesos y amp; " belleza " al intentar consumir todo en la cola:

for (YourObject obj = queue.poll(); obj != null; obj = queue.poll()) {
}

Esto garantizará que salga cuando la cola esté vacía y que continúe extrayendo objetos fuera de ella siempre que no esté vacía.

El ConcurentLinkedQueue es una implementación muy eficiente de espera / bloqueo libre (consulte el javadoc para referencia), así que no solo no necesita sincronizar, sino que la cola no se bloqueará nada, por lo que es prácticamente tan rápida como la no sincronizada. (no seguro para subprocesos) uno.

Solo úselo como lo haría con una colección no concurrente. Las clases Concurrentes [Colección] envuelven las colecciones regulares para que no tenga que pensar en sincronizar el acceso.

Editar: ConcurrentLinkedList no es solo un contenedor, sino una mejor implementación concurrente. De cualquier manera, no tiene que preocuparse por la sincronización.

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