¿Qué es java.util.concurrent.CopyOnWriteArrayList y para qué se utiliza en Java?

| Última modificación: 17 de enero de 2025 | Tiempo de Lectura: 3 minutos

Algunos de nuestros reconocimientos:

Premios KeepCoding

Por cosas de la vida, así como cuando te toca realmente pasar por una situación para aprender algo, justo me pasó que tuve que trabajar en un proyecto donde varios hilos debían acceder y modificar una misma lista. Yo estaba muy confiado en lo que ya conocía, que era el ArrayList común, así que pensé que sería lo más fácil del mundo. Para mi sorpresa, me llovieron errores y problemas de sincronización. Como quien dice, prácticamente a las malas conocí la clase java.util.concurrent.CopyOnWriteArrayList y al fin pude manejar la concurrencia sin necesidad de romperme la cabeza con bloqueos manuales. No te preocupes que por las buenas te explicaré qué es y para qué se utiliza CopyOnWriteArrayList en Java.

java.util.concurrent.CopyOnWriteArrayList qué es

¿Qué es java.util.concurrent.CopyOnWriteArrayList?

Hazte una imagen mental de un tablón de anuncios escolares. De esos donde muestran una lista de estudiantes (elementos de datos) que van a participar en un concurso de talentos. Ese tablón es como un CopyOnWriteArrayList.

Resulta que, al hacer parte del paquete java.util.concurrent, significa que ese tablón está diseñado para ser usado por varias personas (hilos o threads) al mismo tiempo sin causar problemas.

  • Por ejemplo, imagina que varios profesores quieren consultar la lista o añadir a algún estudiante que faltaba.

Entonces, java.util.concurrent.CopyOnWriteArrayList es una implementación de la interfaz List introducida en JDK 1.5 y cada vez que se realiza una operación de escritura (como añadir o modificar elementos), se crea una copia de la lista subyacente, para que los lectores no sean interrumpidos mientras leen.

  • Te pongo un ejemplo más aterrizado a la programación. Piensa en una lista de usuarios conectados en una aplicación, donde muchos usuarios pueden consultar la lista, pero pocos la modifican (al conectarse o desconectarse).

¿Para qué se utiliza java.util.concurrent.CopyOnWriteArrayList? Ejemplos prácticos

Primero, necesitas importar la clase, sino no podrás hacer nada:

import java.util.concurrent.CopyOnWriteArrayList;

Creación de una CopyOnWriteArrayList

Quiero explicarte que puedes crear una lista usando tres constructores principales:

Lista vacía:

CopyOnWriteArrayList<String> lista = new CopyOnWriteArrayList<>();

Desde una colección:

List<String> datos = List.of("A", "B", "C");
CopyOnWriteArrayList<String> lista = new CopyOnWriteArrayList<>(datos);

Desde un arreglo:

String[] array = {"X", "Y", "Z"};
CopyOnWriteArrayList<String> lista = new CopyOnWriteArrayList<>(array);

Operaciones comunes

Añadir elementos

Con el método add() puedes añadir elementos a la lista:

CopyOnWriteArrayList<String> lista = new CopyOnWriteArrayList<>();
lista.add("Elemento 1");
lista.add("Elemento 2");
System.out.println(lista); // Salida: [Elemento 1, Elemento 2]

Iterar elementos

El iterador de CopyOnWriteArrayList crea una copia inmutable de la lista en el momento en que se invoca:

CopyOnWriteArrayList<String> lista = new CopyOnWriteArrayList<>(List.of("A", "B", "C"));
for (String elemento : lista) {
System.out.println(elemento);
}

Modificar elementos

Puedes reemplazar un elemento en una posición específica usando set():

lista.set(1, "Nuevo Elemento");
System.out.println(lista); // Salida: [A, Nuevo Elemento, C]

Eliminar elementos

Aunque CopyOnWriteArrayList soporta remove(), no permite eliminar elementos usando su iterador.

lista.remove("A");
System.out.println(lista); // Salida: [Nuevo Elemento, C]

Ejemplo avanzado: Notificaciones en tiempo real

Te aterrizo todo lo que te he enseñado hasta aquí, para ponértelo en un ejemplo real. Imagina un sistema donde los usuarios reciben notificaciones, pero mientras los leen, se pueden añadir nuevas notificaciones sin interrumpir la lectura.

import java.util.concurrent.CopyOnWriteArrayList;

public class Notificaciones {
public static void main(String[] args) throws InterruptedException {
CopyOnWriteArrayList<String> notificaciones = new CopyOnWriteArrayList<>();
notificaciones.add("Bienvenido");
notificaciones.add("Tienes un nuevo mensaje");

Thread productor = new Thread(() -> {
try {
Thread.sleep(2000);
notificaciones.add("¡Nueva notificación!");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});

Thread consumidor = new Thread(() -> {
for (String notificacion : notificaciones) {
System.out.println("Leyendo: " + notificacion);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});

productor.start();
consumidor.start();

productor.join();
consumidor.join();
}
}

Si observas bien, en este ejemplo, el usuario puede leer las notificaciones existentes mientras se añaden nuevas. CopyOnWriteArrayList asegura que la iteración no cause errores.

Ventajas de java.util.concurrent.CopyOnWriteArrayList

  • Lectura rápida: Lo que más me gusta es que muchos hilos pueden leer la lista al mismo tiempo sin bloquearse entre sí.
  • Consistencia: Los lectores siempre ven una versión consistente de la lista, incluso mientras se está modificando.
  • Manejo automático de concurrencia: No tienes que hacer una sincronización manual.
  • Evita errores comunes: Para tu suerte, no hay más presencia de ConcurrentModificationException.

¡Ojo con esta desventaja!

  • Las modificaciones pueden ser costosas: Algo muy importante que no puedes dejar pasar es que, crear una copia de la lista puede ser costoso en tiempo y memoria si la lista es muy grande. Así que, corrobora primero las necesidades de tu proyecto.

Si quieres simplificar la concurrencia en tus proyectos y asegurarte de que tus listas funcionen bien, aprende todo sobre java.util.concurrent.CopyOnWriteArrayList. En el Bootcamp de Java Full Stack de KeepCoding, te diremos cómo dominar esta clase y también otras herramientas avanzadas de Java que te convertirán en un profesional IT listo para cualquier desafío. ¡Apúntate ahora y transforma tu carrera!

Posts más leídos