3 CopyOnWriteArrayList
Los bloqueos vectoriales y de lista sincronizada tienen gran granularidad, baja eficiencia de simultaneidad y no se pueden editar durante la iteración.
Revise las reglas de diseño del bloqueo de lectura y escritura: se permite que varios subprocesos lean al mismo tiempo y solo un subproceso puede escribir al mismo tiempo (es decir, exclusión mutua escritura-escritura, exclusión mutua lectura-escritura). yLa filosofía de diseño de CopyOnWriteArrayList es que la lectura no está bloqueada en absoluto, y la operación de lectura no se bloqueará al escribir, y solo la escritura y la escritura deben esperar sincrónicamente.
3.1 Un pequeño caso que muestra la función CopyOnWriteArrayList
public class CopyOnWriteArrayListIterator {
public static void main(String[] args) {
// List<String> list = new ArrayList<>();
List<String> list = new CopyOnWriteArrayList<>();
list.add("1");
list.add("3");
list.add("5");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(list);
String next = iterator.next();
System.out.println(next);
if ("3".equals(next)) {
list.add("100");
}
}
}
}
[1, 3, 5]
1
[1, 3, 5]
3
[1, 3, 5, 100]
5
- Durante la iteración de ArrayList, si se modifica la estructura de la lista, se activará el mecanismo Fail-Fast y se lanzarán excepciones de modificación simultáneas.
- CopyOnWriteArrayList puede modificar la lista al iterar, pero el conjunto de resultados de la iteración aún está antes de la modificación.
- Los datos dependen de cuándo se genera el iterador y no se actualizarán después de la iteración.
3.2 Análisis del código fuente
La versión jdk8 de la operación de adición usa ReentrantLock para bloquear y copia internamente los elementos de configuración de la matriz.
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
La versión jdk13 usa bloques de código de sincronización sincronizados y otros cambios no son significativos.
final transient Object lock = new Object(); // 锁
public boolean add(E e) {
synchronized (lock) {
Object[] es = getArray();
int len = es.length;
es = Arrays.copyOf(es, len + 1);
es[len] = e;
setArray(es);
return true;
}
}
No hay ninguna operación de bloqueo para la operación de obtención.
3.3 Desventajas y escenarios aplicables
Desventajas de CopyOnWriteArrayList:
- Problema de consistencia de datos: el contenedor CopyOnWriteArrayList solo puede garantizar la consistencia final de los datos, pero no puede garantizar la consistencia de los datos en tiempo real.
- Problema de ocupación de memoria: La característica del contenedor CopyOnWrite es el mecanismo de copia de la operación de escritura, habrá dos objetos en la memoria durante la operación de escritura.
Escenarios aplicables: CopyOnWriteArrayList es adecuado para situaciones en las que hay muchas operaciones de lectura y pocas operaciones de escritura.