2016-04-18 5 views
5

Sto usando Collections.Synchronizedlist() per rendere sicuro il thread arraylist. Quello che voglio porre è il seguente codice thread-safe vale a dire rimuovere, mentre l'iterazione di lista dalla fine: -Collections.synchronizedlist() remove element while iterating dalla fine

pendingExecutionList = Collections.synchronizedList(new ArrayList<>(initialCapacity)); 

sto creando la lista nel thread principale. e aggiungendo a questa lista da diversi thread. Ma, iterazione e la rimozione è stato fatto solo da un unico filo programmato come segue: -

for (int i = pendingExecutionList.size() - 1; i >= 0; i--) 
{ 
    if (someCondition(pendingExecutionList.get(i))) 
    { 
     process(pendingExecutionList.remove(i)); 
    } 
} 

Il codice precedente viene eseguito da un solo filo mentre più thread stanno aggiungendo a questa lista.

Voglio evitare di utilizzare iteratore su synchronized(list) in quanto non è sicuro.

+2

La risposta è disponibile all'indirizzo http://stackoverflow.com/questions/9468187/collections-synchronizedlist-and-synchronized – alphablue

+2

No, non è thread-safe. [The javadoc] (http://docs.oracle. it/javase/8/docs/api/java/util/Collections.html # synchronizedList-java.util.List-) è estremamente chiaro al riguardo: * È imperativo che l'utente esegua manualmente la sincronizzazione sull'elenco restituito durante l'iterazione su di esso *. –

+0

perché così? Puoi spiegare – maveroid

risposta

1

Se sto capendo correttamente la vostra pipeline del flusso di lavoro, suggerirei di provare qualche variante di uno BlockingQueue invece di uno synchronizedList().

ArrayBlockingQueue consentirebbe di avere una programmazione equa delle esecuzioni e dovrebbe mantenere le cache dei produttori multipli abbastanza calde (a meno che i produttori non inizino a superare il prefetcher della cache, nel qual caso si verificherà una condivisione errata).

Se si è in vena di sperimentare, è possibile dare un'occhiata alle code MPSC (più produttori, singolo consumatore) disponibili al di fuori del JDK, come lo MpscArrayQueue di Nitsan Wakart o lo Disruptor.

+0

Ma la dimensione della lista non è fissa. Può crescere. Quale variante di BlockingQueue preferiresti? – maveroid

+1

Se non si sta sviluppando per l'ambiente mobile o incorporato, è probabile che si sia in grado di ospitare un buffer appropriato assegnato all'avvio dell'applicazione. Come dice Martin Thompson (il ragazzo della simpatia meccanica/uno dei ragazzi del Disruptor), le code illimitate sono spesso usate come un cerotto che può far uscire il sistema dalla memoria (vedi http: // mechanical-sympathy.blogspot.bg/2012/05/apply-back-pressure-when-overloaded.html). Tuttavia, se ritieni di stare meglio con una coda illimitata, puoi provare 'LinkedBlockingQueue' o il non-bloccante' ConcurrentLinkedQueue'. –

2

Invece di tenere il blocco, in realtà si ottiene il blocco una volta per elemento. Ciò comporta il rischio di essere più lento del semplice blocco mentre controlli.

Ti suggerisco di considerare l'utilizzo di un PriorityQueue con un ordine appropriato. Questo ordinerà la coda in modo che quelli che stai per elaborare successivamente saranno all'inizio e il costo della rimozione è relativamente economico indipendentemente dal numero di attività in attesa.

+0

Non sto bloccando da nessuna parte. Puoi spiegare? – maveroid

+0

@maveroid Se si utilizza il metodo su un 'Collections.synchronizedList' dove tutti i metodi sono' sincronizzati' si sta utilizzando un lucchetto se si vuole ammetterlo o meno;) –

+0

Ok, capito ma il blocco è attivo add () e remove() non su iterazione. Destra? – maveroid