¿Cómo logra ConcurrentHashMap la seguridad de subprocesos en Java?

ConcurrentHashMap es una tabla hash que admite la concurrencia total de recuperaciones y una alta concurrencia esperada para las actualizaciones. Esta clase obedece a las mismas especificaciones funcionales que Hashtable e incluye todos los métodos de Hashtable. ConcurrentHashMap está en el paquete java.util.Concurrent.

Sintaxis:

public class ConcurrentHashMap<K,V>
extends AbstractMap<K,V>
implements ConcurrentMap<K,V>, Serializable

Donde K se refiere al tipo de claves mantenidas por este mapa, y V se refiere al tipo de valores mapeados

Necesidad de ConcurrentHashmap:

  • Aunque HashMap tiene muchas ventajas, no se puede usar para subprocesos múltiples porque no es seguro para subprocesos.
  • Aunque se considera que Hashtable es seguro para subprocesos, tiene algunas desventajas. Por ejemplo, Hashtable requiere bloqueo para lectura abierta aunque no afecte al objeto.
  • n HashMap, si un subproceso está iterando sobre un objeto, otro subproceso está tratando de acceder al mismo objeto, lanza ConcurrentModificationException, mientras que hashmap concurrente no lanza ConcurrentModificationException.

¿Cómo fue posible hacer que ConcurrentHashMap sea seguro para subprocesos?

  • La clase java.util.Concurrent.ConcurrentHashMap logra la seguridad de subprocesos al dividir el mapa en segmentos, el bloqueo no se requiere para todo el objeto sino para un segmento, es decir, un subproceso requiere el bloqueo de un segmento.
  • En ConcurrenHashap, la operación de lectura no requiere ningún bloqueo.

Ejemplo 1:

Java

// Java Program to llustarte ConcurrentModificationException
// Using Normal Collections
 
// Importing required classes
import java.util.*;
import java.util.concurrent.*;
 
// Main class extending Thread class
class GFG extends Thread {
 
    // Creating a static HashMap class object
    static HashMap m = new HashMap();
 
    // run() method for the thread
    public void run()
    {
 
        // Try block to check for exceptions
        try {
 
            // Making thread to sleep for 3 seconds
            Thread.sleep(2000);
        }
 
        // Catch block to handle exceptions
        catch (InterruptedException e) {
        }
 
        // Display message
        System.out.println("Child Thread updating Map");
 
        // Putting element in map
        m.put(103, "C");
    }
 
    // Method 2
    // Main driver method
    public static void main(String arg[])
        throws InterruptedException
    {
 
        // Adding elements to map object created above
        // using put() method
        m.put(101, "A");
        m.put(102, "B");
 
        // Creating thread inside main() method
        GFG t = new GFG();
 
        // Starting the thread
        t.start();
 
        // Operating keySet() method and
        // storing it in Set class object
        Set s1 = m.keySet();
 
        // Iterating over Set class object
        // using iterators
        Iterator itr = s1.iterator();
 
        // Holds true till there is single element present
        // inside object
        while (itr.hasNext()) {
 
            // traversing over elements in object
            // using next() method
            Integer I1 = (Integer)itr.next();
 
            // Print statement
            System.out.println(
                "Main Thread Iterating Map and Current Entry is:"
                + I1 + "..." + m.get(I1));
 
            // Making thread to sleep for 3 seconds
            Thread.sleep(3000);
        }
 
        // Printing all elements on console
        System.out.println(m);
    }
}

Producción:

Main Thread Iterating Map and Current Entry is:101...A
Child Thread updating Map
Exception in thread "main" java.util.ConcurrentModificationException
       at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1493)
       at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1516)
       at Main.main(Main.java:30)

Explicación de salida:

La clase utilizada en el programa anterior extiende la clase Thread. Veamos el flujo de control. Entonces, inicialmente, el programa Java anterior contiene un hilo. Cuando encontramos la declaración Main t= new Main(), estamos creando un objeto para una clase que está extendiendo la clase Thread. Por lo tanto, cada vez que llamamos al método t.start(), el subproceso secundario se activa e invoca el método run(). . Ahora el subproceso principal comienza a ejecutarse, siempre que el subproceso secundario actualice el mismo objeto de mapa, generará una excepción denominada ConcurrentModificationException.    

Ahora modifiquemos el programa anterior usando ConcurrentHashMap para resolver la excepción anterior que se generó al ejecutar el programa anterior.

Ejemplo 2:

Java

// Java Program to llustarte ConcurrentModificationException
// Using ConcurrentHashMap
 
// Importing required classes
import java.util.*;
import java.util.concurrent.*;
 
// Main class extending Thread class
class Main extends Thread {
 
    // Creating static concurrentHashMap object
    static ConcurrentHashMap<Integer, String> m
        = new ConcurrentHashMap<Integer, String>();
 
    // Method 1
    // run() method for the thread
    public void run()
    {
 
        // Try block to check for exceptions
        try {
 
            // Making thread to sleep for 2 seconds
            Thread.sleep(2000);
        }
 
        // Catch block to handle the exceptions
        catch (InterruptedException e) {
        }
 
        // Display message
        System.out.println("Child Thread updating Map");
 
        // Inserting element
        m.put(103, "C");
    }
 
    // Method 2
    // Main driver method
    public static void main(String arg[])
        throws InterruptedException
    {
 
        // Adding elements to object created of Map
        m.put(101, "A");
        m.put(102, "B");
 
        // Creating thread inside main() method
        Main t = new Main();
 
        // Starting thread
        t.start();
 
        // Creating object of Set class
        Set<Integer> s1 = m.keySet();
 
        // Creating iterator for traversal
        Iterator<Integer> itr = s1.iterator();
 
        // Condition holds true till there is single element
        // in Set object
        while (itr.hasNext()) {
 
            // Iterating over elements
            // using next() method
            Integer I1 = itr.next();
 
            // Display message
            System.out.println(
                "Main Thread Iterating Map and Current Entry is:"
                + I1 + "..." + m.get(I1));
 
            // Making thread to sleep for 3 seconds
            Thread.sleep(3000);
        }
 
        // Display elements of map objects
        System.out.println(m);
    }
}
Producción

Main Thread Iterating Map and Current Entry is:101...A
Child Thread updating Map
Main Thread Iterating Map and Current Entry is:102...B
Main Thread Iterating Map and Current Entry is:103...C
{101=A, 102=B, 103=C}

Explicación de salida:

la clase utilizada en el programa anterior amplía la clase Thread. Veamos el flujo de control, así como sabemos que en ConcurrentHashMap mientras un subproceso está iterando, los subprocesos restantes pueden realizar cualquier modificación de manera segura. En el programa anterior, el subproceso principal está actualizando el mapa, al mismo tiempo, el subproceso secundario también está intentando actualizar el objeto del mapa. Este Programa no generará ConcurrentModificationException.

Diferencias entre Hashtable, Hashmap, ConcurrentHashmap

Tabla de picadillo

mapa hash

ConcurrentHashMapConcurrentHashMap

Obtendremos Thread-safety bloqueando todo el objeto del mapa. No es seguro para subprocesos. Obtendremos la seguridad de subprocesos sin bloquear el objeto Total Map solo con el bloqueo de nivel de segmento.
Cada operación de lectura y escritura requiere un bloqueo de objeto de mapa de objectstotal. No requiere bloqueo. Las operaciones de lectura se pueden realizar sin bloqueo, pero las operaciones de escritura se pueden realizar con bloqueo a nivel de segmento.
A la vez, solo un subproceso puede operar en el mapa (sincronizado) No se permite el funcionamiento de varios subprocesos a la vez. Lanzará una excepción. A la vez, se permite que varios subprocesos operen en los objetos del mapa de manera segura.
Mientras un subproceso itera el objeto Map, los otros subprocesos no pueden modificar el mapa; de lo contrario, obtenemos ConcurrentModificationException Mientras un subproceso itera el objeto Map, los otros subprocesos no pueden modificar el mapa; de lo contrario, obtenemos ConcurrentModificationException Mientras un subproceso itera el objeto Map, los otros subprocesos pueden modificar el mapa y no obtendremos ConcurrentModificationException
Nulo no está permitido tanto para claves como para valores. HashMap permite una clave nula y múltiples valores nulos Nulo no está permitido tanto para claves como para valores.
Introducido en la versión 1.0 Introducido en la versión 1.2 Introducido en la versión 1.5

Publicación traducida automáticamente

Artículo escrito por akankshakottha y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *