2009-09-16 47 views
31

No estoy seguro de si esta es la forma correcta de sincronizar mi ArrayList.Forma correcta de sincronizar ArrayList en java

Tengo un ArrayListin_queue que se transfiere desde la función registerInQueue.

ArrayList<Record> in_queue = null; 

public void registerInQueue(ArrayList in_queue) 
{ 
    this.in_queue = in_queue; 
} 

Ahora estoy tratando de sincronizarlo. ¿Esto sincroniza correctamente mi objeto in_queue?

List<Record> in_queue_list = Collections.synchronizedList(in_queue); 

synchronized (in_queue_list) { 
    while (in_queue_list.size() > 0) { 
     in_queue_list.remove(0); 
    } 
} 
+5

No se puede actualizar realmente una lista para que se sincronice porque se le está pasando una referencia, por lo que realmente no la posee. Lo que sea que le haya dado la referencia aún podría modificar la lista original que le pasó al mismo tiempo. Independientemente de la sincronización que agregue, a menos que se sepa explícitamente que la lista estará protegida por su bloqueo intrínseco. –

+0

Voy a poner un bloque sincronizado alrededor de cualquier operación en la cola. ¡Gracias! – bob

Respuesta

41

que está sincronizando dos veces, lo que no tiene sentido y, posiblemente, se ralentiza el código: cambios, mientras que la iteración en la lista necesitan un synchronnization lo largo de toda la operación , lo que está haciendo con synchronized (in_queue_list) Usar Collections.synchronizedList() es superfluo en ese caso (crea un contenedor que sincroniza las operaciones individuales).

Sin embargo, como está vaciando la lista por completo, la eliminación iterada del primer elemento es la peor manera posible de hacerlo, sice para cada elemento se deben copiar todos los elementos siguientes, haciendo esto un O (n^2) operación - terriblemente lento para listas más grandes.

En su lugar, simplemente llame al clear() - no es necesario iterar.

Editar: Si necesita la sincronización de un solo método de Collections.synchronizedList() más adelante, entonces esta es la forma correcta:

List<Record> in_queue_list = Collections.synchronizedList(in_queue); 
in_queue_list.clear(); // synchronized implicitly, 

Pero en muchos casos, la sincronización de un solo método es insuficiente (por ejemplo, para todas las iteraciones, o cuando obtiene un valor, haga cálculos basados ​​en él y reemplácelo con el resultado). En ese caso, debe usar la sincronización manual de todas formas, así que Collections.synchronizedList() es una sobrecarga adicional inútil.

+7

La sincronización dos veces aquí no es inútil: garantiza que mientras el ciclo se está ejecutando, nadie más puede modificar la lista. Sin embargo, no usar 'clear()' es un poco exagerado. :) – Bombe

+0

entonces debería hacer algo como: sincronizado ((Lista) in_queue)? – bob

+0

Ok! De hecho, eliminé un poco de código para hacerlo simple. No tendré un problema con clear()/remove(). gracias =] – bob

5

Sí, es la forma correcta, pero se requiere el bloque sincronizado si desea que todas las extracciones juntas sean seguras, a menos que la cola esté vacía, no se permitan las eliminaciones. Supongo que solo quieres operaciones de cola y dequeue seguras, por lo que puedes eliminar el bloque sincronizado.

Sin embargo, hay colas concurrentes muy avanzados en Java, como ConcurrentLinkedQueue

8

Mirando tu ejemplo, creo que ArrayBlockingQueue (o sus hermanos) pueden ser de utilidad. Cuidan la sincronización por usted, por lo que los hilos pueden escribir en la cola o peek/take sin trabajo de sincronización adicional de su parte.

+0

¡Gracias por la sugerencia! Eso es lo que estoy tratando de hacer, aunque no estoy seguro acerca de limitar el tamaño de mi matriz. Lo tendré en cuenta. ;) – bob

+0

Tenga en cuenta que también hay una LinkedBlockingQueue. Y no necesariamente necesitas imponer límites. –

+0

gracias, lo recordaré =] – bob

1

Tomemos una lista normal (implementada por la clase ArrayList) y hagámosla sincronizada. Esto se muestra en la clase SynchronizedListExample. Pasamos el método Collections.synchronizedList una nueva ArrayList of Strings. El método devuelve una lista de cadenas sincronizada. // Aquí es la clase SynchronizedArrayList

package com.mnas.technology.automation.utility; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Iterator; 
import java.util.List; 
import org.apache.log4j.Logger; 
/** 
* 
* @author manoj.kumar 
* @email [email protected] 
* 
*/ 
public class SynchronizedArrayList { 
    static Logger log = Logger.getLogger(SynchronizedArrayList.class.getName()); 
    public static void main(String[] args) {  
     List<String> synchronizedList = Collections.synchronizedList(new ArrayList<String>()); 
     synchronizedList.add("Aditya"); 
     synchronizedList.add("Siddharth"); 
     synchronizedList.add("Manoj"); 
     // when iterating over a synchronized list, we need to synchronize access to the synchronized list 
     synchronized (synchronizedList) { 
      Iterator<String> iterator = synchronizedList.iterator(); 
      while (iterator.hasNext()) { 
       log.info("Synchronized Array List Items: " + iterator.next()); 
      } 
     }  
    } 
} 

Tenga en cuenta que cuando se itera sobre la lista, este acceso se sigue haciendo uso de un bloque sincronizado que se traba en el objeto synchronizedList. En general, iterar sobre una recopilación sincronizada debe realizarse en un bloque sincronizado