1) Il CopyOnWriteArraySet
è un'implementazione abbastanza semplice, in pratica ha un elenco di elementi in un array e quando si modifica l'elenco, copia l'array. Le iterazioni e altri accessi in corso 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) sono piuttosto lente qui, poiché gli array verranno ricercati in tempo lineare.
Utilizzare questo solo per set molto piccoli che verranno letti (ripetuti) spesso e modificati di rado. (Gli oscillatori listener-set sarebbero un esempio, ma questi non sono realmente insiemi e dovrebbero essere comunque utilizzati solo dall'EDT.)
2) Collections.synchronizedSet
semplicemente avvolgerà un blocco sincronizzato attorno a ciascun metodo del set originale. Non si dovrebbe accedere direttamente al set originale. Ciò significa che non è possibile eseguire simultaneamente 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 effettivamente utilizzando il set. Se si utilizza l'iteratore, di solito è necessario sincronizzare esternamente per evitare ConcurrentModificationExceptions quando si modifica il set tra le chiamate iteratore. Le prestazioni saranno come le prestazioni del set originale (ma con un overhead di sincronizzazione e il blocco se utilizzato contemporaneamente).
Utilizzare questo se si ha solo una concorrenza bassa e si vuole essere sicuri che tutte le modifiche siano immediatamente visibili agli altri thread.
3) ConcurrentSkipListSet
è l'implementazione simultanea di SortedSet
, con la maggior parte delle operazioni di base in O (log n). Consente l'aggiunta/rimozione simultanea e la lettura/iterazione, in cui l'iterazione può o non può indicare le modifiche da quando è stato creato l'iteratore. Le operazioni di massa sono semplicemente più chiamate singole e non atomicamente - altri thread possono osservare solo alcuni di essi.
Ovviamente è possibile utilizzare questo solo se si dispone di un ordine totale sui vostri elementi. Questo sembra un candidato ideale per situazioni ad alta concorrenza, per insiemi non troppo grandi (a causa della O (log n)).
4) Per la ConcurrentHashMap
(e il set da esso derivato): Qui opzioni di base sono (in media, se si dispone di una buona e veloce hashCode()
) a O (1) (ma potrebbe degenerare a 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 attualmente in corso scritto). L'iteratore può o non può vedere le modifiche da quando è stato creato e le operazioni di massa non sono atomiche. Il ridimensionamento è lento (come per HashMap/HashSet), quindi cerca di evitare questo stimando la dimensione necessaria alla creazione (e usando circa 1/3 in più di ciò, quando si ridimensiona a 3/4).
Da utilizzare quando si dispone di set di grandi dimensioni, una buona (e veloce) funzione di hash e può stimare la dimensione impostata e la concorrenza necessaria prima di creare la mappa.
5) Esistono altre implementazioni di mappe simultanee che è possibile utilizzare qui?
Solo una correzione visiva in 1), il processo di copia dei dati nel nuovo array deve essere bloccato mediante la sincronizzazione. Pertanto, CopyOnWriteArraySet non evita totalmente la necessità della sincronizzazione. – CaptainHastings
@CaptainHastings grazie, aggiornato. –
Su set basato su ConcurrentHashMap', quindi cerca di evitare questo stimando la dimensione necessaria alla creazione. " La dimensione che fornisci alla mappa deve essere superiore di oltre il 33% rispetto alla stima (o al valore noto), poiché l'insieme viene ridimensionato al 75% del carico. Io uso 'expectedSize + 4/3 + 1' – Daren