Skip to content

3 Copy on write collections

Copy on write collections

La clase CopyOnWriteArrayList crea una versión thread-safe de la clase ArrayList en la que la ejecución de cualquier operación que cambie la estructura de datos, como add(e), set(index, e) o remove(e) produce una nueva copia de la lista en vez de modificar la existente. Está permitido la inserción de valores null en la lista.

Una vez creado un objeto CopyOnWriteArrayList, los cambios en él no afectan a la lista original y viceversa.

Al crear un iterador de un CopyOnWriteArrayList, obtenemos una captura de los datos de la lista en ese momento, por lo que si posteriormente añadimos un elemento a la lista el iterador no será consciente de ello.

La clase CopyOnWriteArrayList fue creada principalmente para permitir la iteración segura sobre los elementos de una lista mientras que la lista original es modificada desde otros hilos. Debido al mecanismo de copia, la operación remove() en el iterado no está permitida, lanzando la excepción UnsupportedOperationException.

List<String> mutableList = new ArrayList<>();
mutableList.add("C");
mutableList.add("C++");
mutableList.add("Java");
List<String> copyOnWriteList = new CopyOnWriteArrayList<>(mutableList);
Iterator<String> iterator = copyOnWriteList.iterator();
// Each modification of the list creates a new copy of the list.
copyOnWriteList.add("Go");
// Null is allowed as element.
copyOnWriteList.add(null);
// Changes in original list don't affect copyOnWriteList.
mutableList.add("Typescript");
System.out.println(copyOnWriteList);
// Changes in copyOnWriteList don't affect original list.
System.out.println(mutableList);
// Iterator has an "old copy" of the list
iterator.forEachRemaining(System.out::println);
Iterator<String> iterator2 = copyOnWriteList.iterator();
while (iterator2.hasNext()) {
    try {
        iterator2.remove();
    } catch (Exception e) {
        System.out.println("remove() in iterator is unsupported");
        return;
    }
}

Por otra parte, tenemos la clase CopyOnWriteArraySet, que nos permite crear una estructura de datos conjunto (set) que envuelve otro conjunto, y que usa internamente un objeto CopyOnWriteArrayList para sus operaciones, por los que comparte todas sus características básicas.

Warning

Evidentemente esta característica puede ser muy costosa en tiempo y memoria, pero puede ser muy eficiente en casos muy concretos, en los que las operaciones de modificación de la estructura de datos son ínfimas en relación al número de operaciones de consulta y recorrido de la misma.