1) Si CopyOnWriteArraySet
tratta di un'implementazione abbastanza semplice: fondamentalmente ha un elenco di elementi in un array e quando si modifica l'elenco, copia l'array. Iterazioni e altri accessi in esecuzione in questo momento continuano con il vecchio array, evitando la necessità di sincronizzazione tra lettori e scrittori (sebbene la scrittura stessa debba essere sincronizzata). Le operazioni di impostazione normalmente veloci (in particolare contains()
) sono piuttosto lente qui, poiché gli array verranno cercati in tempo lineare.
Usalo solo per set veramente piccoli che verranno letti (ripetuti) spesso e cambiati di rado. (I set di listener di swing potrebbero essere un esempio, ma questi non sono realmente set e dovrebbero comunque essere usati solo dall'EDT.)
2) Collections.synchronizedSet
avvolgerà semplicemente un blocco sincronizzato attorno a ciascun metodo dell'insieme originale. Non dovresti accedere direttamente al set originale. Ciò significa che non è possibile eseguire contemporaneamente due metodi dell'insieme (uno bloccherà fino a quando l'altro non termina): questo è sicuro per i thread, ma non si avrà concorrenza se più thread stanno realmente utilizzando l'insieme. Se si utilizza l'iteratore, in genere è comunque necessario sincronizzarsi esternamente per evitare ConcurrentModificationExceptions quando si modifica il set tra le chiamate dell'iteratore. Le prestazioni saranno come quelle del set originale (ma con un certo sovraccarico di sincronizzazione e blocco se utilizzate contemporaneamente).
Usalo se hai solo una bassa concorrenza e vuoi essere sicuro che tutte le modifiche siano immediatamente visibili agli altri thread.
3) ConcurrentSkipListSet
è l' SortedSet
implementazione concorrente , con la maggior parte delle operazioni di base in O (log n). Consente l'aggiunta / rimozione e la lettura / iterazione simultanee, in cui l'iterazione può o meno indicare i cambiamenti dalla creazione dell'iteratore. Le operazioni collettive sono semplicemente più chiamate singole e non atomicamente - altri thread possono osservarne solo alcune.
Ovviamente puoi usarlo solo se hai un po 'di ordine totale sui tuoi elementi. Sembra un candidato ideale per situazioni ad alta concorrenza, per insiemi non troppo grandi (a causa della O (log n)).
4) Per ConcurrentHashMap
(e il set derivato da esso): qui la maggior parte delle opzioni di base sono (in media, se hai una buona e veloce hashCode()
) in O (1) (ma potrebbe degenerare in O (n)), come per HashMap / HashSet. Esiste una concorrenza limitata per la scrittura (la tabella è partizionata e l'accesso in scrittura sarà sincronizzato sulla partizione necessaria), mentre l'accesso in lettura è completamente concorrente a se stesso e ai thread di scrittura (ma potrebbe non vedere ancora i risultati delle modifiche in corso scritto). L'iteratore può o meno vedere le modifiche da quando è stato creato e le operazioni in blocco non sono atomiche. Il ridimensionamento è lento (come per HashMap / HashSet), quindi cerca di evitarlo stimando le dimensioni necessarie al momento della creazione (e usandone circa 1/3 in più, dato che si ridimensiona quando è pieno per 3/4).
Utilizzalo quando hai set di grandi dimensioni, una buona (e veloce) funzione hash e puoi stimare la dimensione del set e la concorrenza necessaria prima di creare la mappa.
5) Esistono altre implementazioni di mappe simultanee che è possibile utilizzare qui?