2012-07-06 13 views
56

Ho un elenco di array precompilato. E ho più thread che rimuoveranno gli elementi dall'elenco di array. Ogni thread chiama il metodo di rimozione in basso e rimuove un elemento dall'elenco. Il seguente codice mi dà un comportamento coerente?Elenco Sincronizzato Java

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

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

Grazie!

risposta

52

Sì, basta fare attenzione se si sta ripetendo anche l'elenco, perché in questo caso sarà necessario sincronizzarsi su di esso. Dal Javadoc:

E 'indispensabile che l'utente sincronizzare manualmente nella lista restituita quando l'iterazione su di esso:

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

In alternativa, è possibile utilizzare CopyOnWriteArrayList che è più lento per la scrittura, ma doesn' Ho questo problema.

+0

Ho una domanda sul filo di sicurezza [qui] (https://stackoverflow.com/questions/46997971/concurrently-reading-a-map-while-a-single-background-thread-regularly-modifies -i) Volevo vedere se puoi aiutarmi? – john

+0

Ottimo suggerimento per 'CopyOnWriteArrayList'. Grazie! – FrVaBe

23

Questo dovrebbe andare bene finché non è necessario che il metodo "rimuovi" sia atomico.

In altre parole, se "fa qualcosa" controlla che l'elemento venga visualizzato più di una volta nell'elenco, ad esempio, è possibile che il risultato di tale verifica sia errato quando si raggiunge la riga successiva.

Inoltre, assicurarsi che si sincronizza sulla lista quando l'iterazione:

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

Come accennato da Peter Lawrey, CopyOnWriteArrayList può rendere la vita più facile e in grado di fornire una migliore performance in un ambiente altamente concorrente.

10

Da Collections#synchronizedList(List) javadoc

Restituisce un sincronizzato lista (thread-safe) sostenuto dalla lista specificata. Per garantire l'accesso seriale, è fondamentale che tutti gli l'accesso alla lista di supporto sia eseguito attraverso l'elenco restituito ... È imperativo che l'utente esegua manualmente la sincronizzazione nell'elenco restituito durante l'iterazione su di esso. La mancata osservanza di questo consiglio può comportare un comportamento non deterministico.

0

Fornirà un comportamento coerente per le operazioni di aggiunta/rimozione. Ma durante l'iterazione devi sincronizzarti esplicitamente. Refer this link

0

Sì, funzionerà correttamente poiché l'elenco contiene synchronized. Ti suggerisco di usare 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

Si possono avere 2 problemi diffent con le liste:
1) Se fate una modifica all'interno di un'iterazione, anche se in un ambiente filo mono, si avrà ConcurrentModificationException come in questo esempio che segue:

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

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

Quindi, per evitare questo problema, si può fare:

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

2) Il secondo problema potrebbe essere multi threading ambiente. Come accennato in precedenza, è possibile utilizzare sincronizzato (elenco) per evitare eccezioni.

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

Prova sempre ad aggiungere qualche descrizione correlata alla tua risposta. –

+1

Puoi espandere la tua risposta per includere una spiegazione del tuo codice? Aiuta il lettore più di quanto tu possa pensare. – gunr2171