Buscar..


Introducción

Una colección concurrente es una [colección] [1] que permite el acceso por más de un hilo al mismo tiempo. Normalmente, diferentes hilos pueden recorrer el contenido de la colección y agregar o eliminar elementos. La colección es responsable de garantizar que la colección no se corrompa. [1]: http://stackoverflow.com/documentation/java/90/collections#t=201612221936497298484

Colecciones a prueba de hilos

De forma predeterminada, los distintos tipos de Colección no son seguros para subprocesos.

Sin embargo, es bastante fácil hacer una colección segura para subprocesos.

List<String> threadSafeList = Collections.synchronizedList(new ArrayList<String>());
Set<String> threadSafeSet = Collections.synchronizedSet(new HashSet<String>());
Map<String, String> threadSafeMap = Collections.synchronizedMap(new HashMap<String, String>());

Cuando realice una colección segura para subprocesos, nunca debe acceder a ella a través de la colección original, solo a través de la envoltura segura para hilos.

Java SE 5

A partir de Java 5, java.util.collections tiene varias colecciones nuevas seguras para subprocesos que no necesitan los diversos métodos de Collections.synchronized .

List<String> threadSafeList = new CopyOnWriteArrayList<String>();
Set<String> threadSafeSet = new ConcurrentHashSet<String>();
Map<String, String> threadSafeMap = new ConcurrentHashMap<String, String>();

Colecciones concurrentes

Las colecciones concurrentes son una generalización de las colecciones seguras para subprocesos, que permiten un uso más amplio en un entorno concurrente.

Si bien las colecciones seguras para subprocesos tienen la adición o eliminación segura de elementos de varios subprocesos, no necesariamente tienen una iteración segura en el mismo contexto (es posible que uno no pueda recorrer la colección en un subproceso en una secuencia, mientras que otro lo modifica agregando quitando elementos).

Aquí es donde se utilizan las colecciones concurrentes.

Como la iteración suele ser la implementación básica de varios métodos masivos en colecciones, como addAll , removeAll , o también la copia de colecciones (a través de un constructor u otros medios), clasificación, ... el caso de uso de colecciones concurrentes es en realidad bastante grande.

Por ejemplo, Java SE 5 java.util.concurrent.CopyOnWriteArrayList es una implementación de Lis t segura para subprocesos, su javadoc afirma:

El método del iterador de estilo "instantánea" utiliza una referencia al estado de la matriz en el punto en que se creó el iterador. Esta matriz nunca cambia durante la vida útil del iterador, por lo que la interferencia es imposible y se garantiza que el iterador no lanzará ConcurrentModificationException.

Por lo tanto, el siguiente código es seguro:

public class ThreadSafeAndConcurrent {

public static final List<Integer> LIST = new CopyOnWriteArrayList<>();

public static void main(String[] args) throws InterruptedException {
    Thread modifier = new Thread(new ModifierRunnable());
    Thread iterator = new Thread(new IteratorRunnable());
    modifier.start();
    iterator.start();
    modifier.join();
    iterator.join();
}

public static final class ModifierRunnable implements Runnable {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 50000; i++) {
                LIST.add(i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public static final class IteratorRunnable implements Runnable {
    @Override
    public void run() {
        try {
            for (int i = 0; i < 10000; i++) {
                long total = 0;
                for(Integer inList : LIST) {
                    total += inList;
                }
                System.out.println(total);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
}

Otra colección concurrente con respecto a la iteración es ConcurrentLinkedQueue , que establece:

Los iteradores son débilmente consistentes, devolviendo elementos que reflejan el estado de la cola en algún momento en o desde la creación del iterador. No lanzan java.util.ConcurrentModificationException, y pueden proceder simultáneamente con otras operaciones. Los elementos contenidos en la cola desde la creación del iterador se devolverán exactamente una vez.

Uno debe revisar los javadocs para ver si una colección es concurrente o no. Los atributos del iterador devueltos por el método iterator() ("falla rápidamente", "débilmente consistente", ...) es el atributo más importante que debe buscarse.

Hilo seguro pero ejemplos no concurrentes

En el código anterior, cambiando la declaración LIST a

public static final List<Integer> LIST = Collections.synchronizedList(new ArrayList<>());

Podría (y estadísticamente lo hará en la mayoría de las arquitecturas de CPU / núcleo con múltiples CPU) dar lugar a excepciones.

Las colecciones sincronizadas de los métodos de utilidad de Collections son seguras para subprocesos para la adición / eliminación de elementos, pero no la iteración (a menos que la colección subyacente que se le pasa ya lo sea).

Inserción en el mapa de hash concurrente

public class InsertIntoConcurrentHashMap
{

    public static void main(String[] args)
    {
        ConcurrentHashMap<Integer, SomeObject> concurrentHashMap = new ConcurrentHashMap<>();

        SomeObject value = new SomeObject();
        Integer key = 1;

        SomeObject previousValue = concurrentHashMap.putIfAbsent(1, value);
        if (previousValue != null)
        {
            //Then some other value was mapped to key = 1. 'value' that was passed to
            //putIfAbsent method is NOT inserted, hence, any other thread which calls
            //concurrentHashMap.get(1) would NOT receive a reference to the 'value'  
            //that your thread attempted to insert. Decide how you wish to handle             
            //this situation.
        }

       else
       {
            //'value' reference is mapped to key = 1.
       }
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow