¿Cómo usar ConcurrentLinkedQueue?

¿Cómo uso un ConcurrentLinkedQueue en Java?
Usando este LinkedQueue , ¿debo preocuparme por la concurrencia en la cola? ¿O solo 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. ¿Derecha?


EDITAR: Lo que trato 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: ¿tengo que hacer esto en el método remove?

 while (queue.size() == 0){ wait(); queue.poll(); } 

Solo tengo un consumidor y un productor.

No, los métodos no necesitan sincronizarse, y no es necesario definir ningún método; ya están en ConcurrentLinkedQueue, solo úsalos. ConcurrentLinkedQueue realiza todas las operaciones de locking y otras operaciones que necesita internamente; su (s) productor (es) agrega (n) datos a la cola y sus consumidores sondean para ello.

Primero, crea tu cola:

 Queue queue = new ConcurrentLinkedQueue(); 

Ahora, donde sea que estés creando tus objetos de productor / consumidor, pasa la cola para que tengan un lugar donde colocar sus objetos (podrías 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 agrega cosas a él en tu productor:

 queue.offer(myObject); 

y saque cosas en su consumidor (si la cola está vacía, poll () devolverá nulo, así que compruébelo):

 YourObject myObject = queue.poll(); 

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 una LinkedBlockingQueue y utilizar 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 según sus circunstancias.

Si solo tiene un hilo colocando cosas en la cola, y otro hilo 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. Sus necesidades probablemente se cumplirán mediante el uso de:

 Queue queue = Collections.synchronizedList(new LinkedList()); 

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 explica Jared). NO PUEDE hacer esto con una ConcurrentLinkedQueue, ya que todas las operaciones se realizan SIN bloquear en la instancia (usando variables java.util.concurrent.atomic). NO necesitarás hacer esto si deseas bloquear mientras la cola está vacía, porque poll () simplemente devolverá nulo mientras la cola está vacía, y poll () es atómica. Verifique si poll () devuelve nulo. Si lo hace, espere (), luego intente de nuevo. No es necesario bloquearlo

Finalmente:

Honestamente, solo usaría LinkedBlockingQueue. Todavía es excesivo para su aplicación, pero las probabilidades son que funcionará bien. Si no es lo suficientemente eficiente (¡PERFIL!), Siempre puedes probar otra cosa, y eso significa que no tienes que lidiar con CUALQUIER cosa sincronizada:

 BlockingQueue queue = new LinkedBlockingQueue(); queue.put(myObject); // Blocks until queue isn't full. YourObject myObject = queue.take(); // Blocks until queue isn't empty. 

Todo lo demás es lo mismo. Probablemente, put no bloqueará, porque no es probable que ponga dos mil millones de objetos en la cola.

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 simultáneas están sincronizadas para usted. En otras palabras, cada llamada individual a la cola está garantizada por subprocesos sin ninguna acción de su parte. Lo que no está garantizado para seguridad de subprocesos son las operaciones que realice en la colección que no sean atómicas.

Por ejemplo, esto es seguro para la realización de hilos 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 no son automáticamente seguras en cuanto a los hilos:

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

El último no es inseguro, ya que es muy posible que, entre el momento en que se invoque Vacíe y se llame a la encuesta de tiempo, otros hilos hayan agregado o eliminado elementos de la cola. La forma segura de realizar esto es así:

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

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

Use la encuesta para obtener el primer elemento y agréguela para agregar un nuevo elemento. Eso es todo, sin sincronización ni nada más.

Esto es probablemente lo que está buscando en términos de seguridad de hilo y “bondad” cuando intenta 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 mientras no esté vacía.

ConcurentLinkedQueue es una implementación muy eficiente de espera / locking (consulte el javadoc como referencia), por lo que no solo no necesita sincronizar, sino que la cola no bloqueará nada, por lo que es prácticamente tan rápido como un hilo no sincronizado (no hilo) seguro) uno.

Simplemente úsalo como lo harías con una colección no simultánea. Las clases Concurrent [Colección] envuelven las colecciones regulares para que no tenga que pensar en sincronizar el acceso.

Editar: ConcurrentLinkedList no es solo una envoltura, sino una mejor implementación simultánea. De cualquier manera, no tiene que preocuparse por la sincronización.