1) La CopyOnWriteArraySet
implementación es bastante simple: básicamente tiene una lista de elementos en una matriz y, al cambiar la lista, copia la matriz. Las iteraciones y otros accesos que se están ejecutando en este momento continúan con la matriz anterior, evitando la necesidad de sincronización entre lectores y escritores (aunque la escritura misma debe sincronizarse). Las operaciones de configuración normalmente rápidas (especialmente contains()
) son bastante lentas aquí, ya que las matrices se buscarán en tiempo lineal.
Use esto solo para conjuntos realmente pequeños que se leerán (iterarán) con frecuencia y se cambiarán raramente. (Swing listener-sets sería un ejemplo, pero estos no son realmente sets, y de todos modos solo deberían usarse desde el EDT).
2) Collections.synchronizedSet
simplemente envolverá un bloque sincronizado alrededor de cada método del conjunto original. No debe acceder al conjunto original directamente. Esto significa que no se pueden ejecutar simultáneamente dos métodos del conjunto (uno se bloqueará hasta que el otro termine): esto es seguro para subprocesos, pero no tendrá concurrencia si varios subprocesos realmente están usando el conjunto. Si usa el iterador, generalmente aún necesita sincronizar externamente para evitar ConcurrentModificationExceptions al modificar el conjunto entre llamadas de iterador. El rendimiento será como el rendimiento del conjunto original (pero con cierta sobrecarga de sincronización y bloqueo si se usa simultáneamente).
Use esto si solo tiene poca concurrencia y desea asegurarse de que todos los cambios sean visibles de inmediato para los otros subprocesos.
3) ConcurrentSkipListSet
es la SortedSet
implementación concurrente , con la mayoría de las operaciones básicas en O (log n). Permite agregar / eliminar y leer / iterar simultáneamente, donde la iteración puede o no informar sobre los cambios desde que se creó el iterador. Las operaciones masivas son simplemente llamadas individuales múltiples, y no atómicamente; otros subprocesos pueden observar solo algunas de ellas.
Obviamente, puede usar esto solo si tiene un orden total en sus elementos. Esto parece un candidato ideal para situaciones de alta concurrencia, para conjuntos no demasiado grandes (debido a la O (log n)).
4) Para el ConcurrentHashMap
(y el Conjunto derivado de él): Aquí las opciones más básicas son (en promedio, si tiene un buen y rápido hashCode()
) en O (1) (pero podría degenerar en O (n)), como para HashMap / HashSet. Hay una concurrencia limitada para la escritura (la tabla está particionada, y el acceso de escritura se sincronizará en la partición necesaria), mientras que el acceso de lectura es totalmente concurrente para sí mismo y los hilos de escritura (pero es posible que aún no vean los resultados de los cambios que se están realizando actualmente escrito). El iterador puede ver o no cambios desde que se creó, y las operaciones masivas no son atómicas. El cambio de tamaño es lento (como para HashMap / HashSet), por lo tanto, trate de evitar esto estimando el tamaño necesario en la creación (y usando aproximadamente 1/3 más de eso, ya que cambia el tamaño cuando está 3/4 lleno).
Use esto cuando tenga conjuntos grandes, una función hash buena (y rápida) y pueda estimar el tamaño del conjunto y la concurrencia necesaria antes de crear el mapa.
5) ¿Hay otras implementaciones de mapas concurrentes que uno podría usar aquí?