2011-09-07 14 views
15

documentazione sul synchronizedList afferma che,Java lista sincronizzato per il ciclo

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

La mancata osservanza di questo consiglio può comportare un comportamento non deterministico.

Questo sembra abbastanza chiaro, ma volevo solo confermare che un ciclo per ogni ciclo è proibito. Ad esempio, non posso fare qualcosa come segue, giusto?

List<MyType> list = Collections.synchronizedList(new ArrayList(<MyType>)); 
... 
synchronized(list){ 
    for(MyType m : list){ 
     foo(m); 
     m.doSomething(); 
    } 
} 
+4

Perché questo è proibito? Il codice byte generato è praticamente lo stesso. Foreach utilizza l'iteratore ... –

+0

Sembra che la lista sincronizzata decida solo le chiamate al metodo con sincronizzazione, ma presenta delle limitazioni. Forse i progettisti dovrebbero aver decorato anche il metodo iteratore e restituire un iteratore sincronizzato. Il for è nella lingua e non può essere decorato così facilmente XD: –

risposta

26

Sì, è possibile - la vostra migliorato per ciclo è fondamentalmente lo stesso come il tuo codice che usa esplicitamente l'iteratore. Si riduce allo stesso codice: chiama solo iterator() e quindi si alterna tra le chiamate e hasNext().

+0

se cancelliamo l'elemento da iteratore, mentre usando hasNext()/next() è ok. ma se cancelliamo qualche elemento dalla lista quando lo iteriamo attraverso il ciclo for (int: list) - genererà ConcurentModificationException. Quindi non è lo stesso in questo contesto. – ses

+0

@ses: ma il codice fornito non usa 'remove'. Un ciclo perfezionato usa l'iteratore (per i non-array), ma ciò non significa che puoi fare tutto con un ciclo for avanzato che potresti fare direttamente con l'iteratore. –

+0

Questo è ... Puoi guardare la mia domanda qui: http://stackoverflow.com/questions/16742763/using-iterator-over-for-loop-in-concurrent-java-app – ses

1

È possibile farlo. Il ciclo foreach compila (quasi) lo stesso bytecode del ciclo while. I tasti sono:

  1. Si sincronizza il blocco attorno al ciclo perché l'elenco può cambiare mentre si sta iterando su di esso.
  2. Si utilizza l'elenco come oggetto su cui si sta eseguendo la sincronizzazione, poiché l'implementazione di questa classe si blocca su se stessa (tramite metodi sincronizzati).
1

Naturalmente è possibile, l'unico problema che vedo qui è un problema di prestazioni, se il metodo dosomething() o foo(m) sono costosi da eseguire, si avrà un costo delle prestazioni. Anche la dimensione della tua collezione è importante da tenere in considerazione durante il loop in un blocco sincronizzato, poiché quando un thread acquisisce il blocco, mentre si trova nel blocco sincronizzato, il looping di un'enorme raccolta spinge gli altri thread ad attendere.

+0

Alcune formattazioni, qualche parola in più e in realtà potrebbe essere una risposta;] – t3chb0t