Aunque tanto los ArrayList sincronizados como CopyOnWriteArrayList nos proporcionan
seguridad cuando trabajamos con threads (subprocesos), y pueden ser usados cuando necesitemos que una lista se comparta entre varios threads, existe una sutil diferencia entre estas dos implementaciones: un ArrayList sincronizado, como su nombre lo indica, es una colección sincronizada mientras que un CopyOnWriteArrayList es una colección concurrente.
¿Qué significa esto? Significa que CopyOnWriteArrayList está diseñado teniendo en cuenta escenarios de concurrencia y es más escalable que un ArrayList sincronizado, siempre y cuando la lista se use principalmente para operaciones de lectura. Un ArrayList en Java no es sincronizado por defecto, por lo que no puede usarse directamente en un entorno de subprocesos (threads) múltiples, donde la lista se accede y se modifica mediante varios subprocesos. Para usar un ArrayList en dicho entorno, primero debemos obtener una lista sincronizada llamando a Collections.synchronizedList().
CopyOnWriteArrayList aprovecha también esta funcionalidad y proporciona lecturas sin bloqueos, lo cual significa un rendimiento mucho mejor si hay más hilos tratando de realizar operaciones de lectura y muy pocos o incluso ninguno realizando operaciones de escritura.
¿Qué significa esto? Significa que CopyOnWriteArrayList está diseñado teniendo en cuenta escenarios de concurrencia y es más escalable que un ArrayList sincronizado, siempre y cuando la lista se use principalmente para operaciones de lectura. Un ArrayList en Java no es sincronizado por defecto, por lo que no puede usarse directamente en un entorno de subprocesos (threads) múltiples, donde la lista se accede y se modifica mediante varios subprocesos. Para usar un ArrayList en dicho entorno, primero debemos obtener una lista sincronizada llamando a Collections.synchronizedList().
Esta lista sincronizada logra
seguridad en el thread al bloquear toda la colección, lo que significa
que si un hilo está leyendo de una lista y al mismo tiempo otro también intenta leer de la misma, estos irán uno por uno, es decir, que múltiples hilos pueden
leer desde un mismo objeto sin ningún problema.
CopyOnWriteArrayList aprovecha también esta funcionalidad y proporciona lecturas sin bloqueos, lo cual significa un rendimiento mucho mejor si hay más hilos tratando de realizar operaciones de lectura y muy pocos o incluso ninguno realizando operaciones de escritura.
En
resumen, la principal diferencia entre un ArrayList sincronizado y
CopyOnWriteArrayList en Java proviene del hecho de cómo logran seguridad en sus operaciones entre hilos y qué tan escalables son.
List Sincronizado vs CopyOnWriteArrayList
En primer lugar, debemos de saber que Java hace uso del framework Collection, lo que nos evita usar muchas variantes de
clases cunado tengamos que trabajar con listas de datos; así pues, el framework Collection nos proporciona wrappers mediante la clase java.util.Collections; por ejemplo, si necesitamos un ArrayList de solo lectura, podemos obtenerlo
llamando a Collections.unmodifiableList(), y de forma similar, si necesitamos una lista sincronizada, podemos obtenerla llamando a Collections.synchronizedList().
Por lo general, estas implementaciones venían funcionado bien, pero con el tiempo, las aplicaciones Java se han vuelto más
sofisticadas y cuando estas clases se exponen en entornos altamente concurrentes, se convierten en un cuello de botella. Una
vez que los ingenieros detrás de Java se dieron cuenta de este hecho, vieron que necesitaban de colecciones que fuesen más escalables y pudiesen ofrecer mejor rendimiento cuando se utilizaran en un entorno de múltiples subprocesos (threads), y así es como a partir de Java 5 se incorporó un nuevo conjunto de clases para el manejo de colecciones denominado Concurrent
Collections.
Esta
librería incluye alternativas concurrentes de las colecciones más
populares, como por ejemplo ConcurrentHashMap para HashMap y CopyOnWriteArrayList
para ArrayList. Estas implementaciones están diseñadas específicamente
para escenarios de alta concurrencia y es por eso que logran la seguridad del thread de
una forma más sofisticada que simplemente bloquear toda la colección.
Recapitulemos entonces algunas de las diferencias claves entre un ArrayList sincronizado y CopyOnWriteArrayList en Java:
1) La primer diferencia entre un ArrayList sincronizado y CopyOnWriteArrayList proviene del hecho de cómo logran la seguridad del thread. Una lista sincronizada bloquea toda la colección para proporcionar sincronización y seguridad en los threads, mientras que CopyOnWriteArrayList no bloquea la colección y cuando un thread escribe en la lista, simplemente reemplaza la lista copiando sus elementos. De esta manera, proporciona acceso simultáneo a la lista para varios threads sin bloqueos y, dado que las operaciones de lectura son seguras cuando se ejecutan en distintos threads, quiere decir que no hay dos threads que puedan estar escribiendo en la misma lista de datos al tiempo.
2) La segunda diferencia proviene del hecho de cómo se comportan sus iteradores. El iterador devuelto desde un ArrayList sincronizado es un fail-fast iterator (Iterador que puede fallar rápido), mientras que el iterador devuelto por CopyOnWriteArrayList es un fail-safe iterator (Iterador a prueba de fallos), es decir, no lanzará ConcurrentModifcationException incluso en escenarios donde la lista se modifique mientras un thread esté iterando sobre ella.
3) En tercer lugar, y no menos importante, una de las principales diferencias entre CopyOnWriteArrayList y ArrayList es el rendimiento, especialmente si necesitamos que la lista se utilice principalmente con fines de solo lectura. Es probable que CopyOnWriteArrayList supere al ArrayList sincronizado si este es el caso, pero si la lista está expuesta a operaciones de lectura y escritura, es probable que el ArrayList sincronizado presente un mejor rendimiento.
Otra cosa muy importante que se debe tener en cuenta es el tamaño que tiene el ArrayList, o incluso el que pueda llegar a alcanzar, ya que debemos analizar según la necesidad que tengamos, si su gran costo de copiado (después de una operación de lectura) es lo suficientemente alto como para compensar el costo de bloqueo, pero si el ArrayList es pequeño, podría usarse CopyOnWriteArrayList sin preocuparse por este tipo de inconvenientes.
Estas son entonces las diferencias entre un ArrayList sincronizado y CopyOnWriteArrayList en Java que debes tener en cuenta y que te permitirán saber en qué escenario es mejor usar uno u otro. Básicamente,
CopyOnWriteArrayList es una mejor opción si se accede principalmente a
una lista para leer datos, pero si las operaciones de escritura son considerablemente altas,
la mejor opción es usar un ArrayList sincronizado porque el costo de copiar la
lista con cada operación sería mayor que la ganancia de sacrificar el bloqueo de la lista.
Otro aspecto que nos permitirá saber rápidamente qué opción escoger, es ver si necesitamos que el iterador detecte modificaciones concurrentes cuando se está recorriendo la lista o si se desea modificar la colección a través del iterador; en estos casos la opción idónea es un ArrayList Sincronizado.
No hay comentarios.:
Publicar un comentario