2012-07-06 13 views
56

Tengo una lista de conjuntos precomplementada. Y tengo múltiples hilos que eliminarán elementos de la lista de arreglos. Cada hilo llama al método de eliminación a continuación y elimina un elemento de la lista. ¿El siguiente código me da un comportamiento consistente?Java Lista sincronizada

ArrayList<String> list = Collections.synchronizedList(new ArrayList<String>()); 

void remove(String item) 
{ 
    do something; (doesn't work on the list) 
    list.remove(item); 
} 

¡Gracias!

Respuesta

52

Sí, solo tenga cuidado si también está iterando sobre la lista, porque en este caso tendrá que sincronizar en ella. Desde el Javadoc:

Es imperativo que el usuario sincronizar manualmente en la lista devuelta cuando se itera sobre ella:

List list = Collections.synchronizedList(new ArrayList()); 
    ... 
synchronized (list) { 
    Iterator i = list.iterator(); // Must be in synchronized block 
    while (i.hasNext()) 
     foo(i.next()); 
} 

O bien, puede utilizar CopyOnWriteArrayList que es más lento para las escrituras, pero doesn' Tengo este problema.

+0

Tengo una pregunta sobre la seguridad de la rosca [aquí] (https://stackoverflow.com/questions/46997971/concurrently-reading-a-map-while-a-single-background-thread-regularly-modifies -i) entonces quería ver si me puedes ayudar? – john

+0

Gran sugerencia para 'CopyOnWriteArrayList'. ¡Gracias! – FrVaBe

23

Eso debería estar bien siempre y cuando no requiera que el método "quitar" sea atómico.

En otras palabras, si el "hacer algo" comprueba que el elemento aparece más de una vez en la lista, por ejemplo, es posible que el resultado de esa verificación sea incorrecto cuando llegue a la siguiente línea.

Además, asegúrese de sincronizar en la lista cuando se repite:

synchronized(list) { 
    for (Object o : list) {} 
} 

Como se ha mencionado por Peter Lawrey, CopyOnWriteArrayList puede hacer su vida más fácil y puede proporcionar un mejor rendimiento en un entorno altamente concurrente.

10

De Collections#synchronizedList(List) javadoc

Devuelve una lista sincronizada (thread-safe) respaldado por la lista especificado. Para garantizar el acceso en serie, es fundamental que todo el acceso a la lista de respaldo se realice a través de la lista devuelta ... Es imprescindible que el usuario se sincronice manualmente en la lista devuelta al iterar sobre ella. El incumplimiento de este consejo puede dar como resultado un comportamiento no determinista.

0

Proporcionará un comportamiento uniforme para las operaciones de agregar/quitar. Pero al iterar tienes que sincronizar explícitamente. Refer this link

0

Sí, funcionará bien ya que tiene synchronized la lista. Le sugiero que use CopyOnWriteArrayList.

CopyOnWriteArrayList<String> cpList=new CopyOnWriteArrayList<String>(new ArrayList<String>()); 

    void remove(String item) 
    { 
     do something; (doesn't work on the list) 
       cpList..remove(item); 
    } 
1

Puede tener 2 problemas diffent con listas:
1) Si usted hace una modificación dentro de una iteración a pesar de que en un entorno hilo mono, tendrá ConcurrentModificationException como en este ejemplo siguiente:

List<String> list = new ArrayList<String>(); 
for (int i=0;i<5;i++) 
    list.add("Hello "+i); 

for(String msg:list) 
    list.remove(msg); 

Por lo tanto, para evitar este problema, que puede hacer:

for(int i=list.size()-1;i>=0;i--) 
    list.remove(i); 

2) El segundo problema podría ser múltiples subprocesos ambiente. Como se mencionó anteriormente, puede usar synchronized (list) para evitar excepciones.

-3
synchronized(list) { 
    for (Object o : list) {} 
} 
+10

Siempre intente agregar alguna descripción relacionada a su respuesta. –

+1

¿Puede ampliar su respuesta para incluir una explicación de su código? Le ayuda al lector más de lo que piensas. – gunr2171

Cuestiones relacionadas