1) A CopyOnWriteArraySet
implementação é bastante simples - basicamente possui uma lista de elementos em uma matriz e, ao alterar a lista, copia a matriz. As iterações e outros acessos em execução no momento continuam com a matriz antiga, evitando a necessidade de sincronização entre leitores e gravadores (embora a própria gravação precise ser sincronizada). As operações de configuração normalmente rápida (especialmente contains()
) são bastante lentas aqui, pois as matrizes serão pesquisadas em tempo linear.
Use isso apenas para conjuntos realmente pequenos que serão lidos (iterados) com frequência e alterados raramente. (Swings listener-sets seria um exemplo, mas na verdade não são conjuntos e deve ser usado apenas no EDT de qualquer maneira.)
2) Collections.synchronizedSet
simplesmente envolverá um bloco sincronizado em torno de cada método do conjunto original. Você não deve acessar o conjunto original diretamente. Isso significa que não há dois métodos do conjunto que podem ser executados simultaneamente (um bloqueará até que o outro termine) - isso é seguro para threads, mas você não terá simultaneidade se vários threads realmente estiverem usando o conjunto. Se você usar o iterador, geralmente ainda precisará sincronizar externamente para evitar ConcurrentModificationExceptions ao modificar o conjunto entre as chamadas do iterador. O desempenho será semelhante ao desempenho do conjunto original (mas com alguma sobrecarga de sincronização e bloqueio, se usado simultaneamente).
Use isso se você tiver baixa simultaneidade e desejar garantir que todas as alterações sejam imediatamente visíveis para os outros threads.
3) ConcurrentSkipListSet
é a SortedSet
implementação simultânea , com as operações mais básicas em O (log n). Permite adicionar / remover e ler / iterar simultaneamente, onde a iteração pode ou não informar sobre as alterações desde que o iterador foi criado. As operações em massa são simplesmente várias chamadas únicas, e não atomicamente - outros threads podem observar apenas algumas delas.
Obviamente, você pode usar isso apenas se tiver alguma ordem total em seus elementos. Parece um candidato ideal para situações de alta simultaneidade, para conjuntos não muito grandes (por causa do O (log n)).
4) Para o ConcurrentHashMap
(e o conjunto derivado dele): Aqui as opções mais básicas são (em média, se você tem um bom e rápido hashCode()
) em O (1) (mas pode degenerar em O (n)), como no HashMap / HashSet. Há uma simultaneidade limitada para gravação (a tabela é particionada e o acesso de gravação será sincronizado na partição necessária), enquanto o acesso de leitura é totalmente simultâneo a si e aos encadeamentos de gravação (mas ainda não pode ver os resultados das alterações atualmente sendo escrito). O iterador pode ou não ver alterações desde que foi criado, e as operações em massa não são atômicas. O redimensionamento é lento (como no HashMap / HashSet), portanto, tente evitar isso estimando o tamanho necessário na criação (e usando cerca de 1/3 a mais disso, pois é redimensionado quando 3/4 está cheio).
Use isso quando você tiver conjuntos grandes, uma boa (e rápida) função de hash e puder estimar o tamanho do conjunto e a simultaneidade necessária antes de criar o mapa.
5) Existem outras implementações simultâneas de mapas que alguém poderia usar aqui?