Java ConcurrentHashMap
Mapa de hash concurrente de Java
En este tutorial, aprenderemos sobre la clase Java ConcurrentHashMap y sus operaciones con la ayuda de ejemplos.
El ConcurrentHashMap
La clase del marco de colecciones de Java proporciona un mapa seguro para subprocesos. Es decir, varios subprocesos pueden acceder al mapa a la vez sin afectar la consistencia de las entradas en un mapa.
Implementa la interfaz ConcurrentMap.
Crear un mapa hash concurrente
Para crear un hashmap concurrente, debemos importar el java.util.concurrent.ConcurrentHashMap
paquete primero. Una vez que importamos el paquete, así es como podemos crear hashmaps simultáneos en Java.
// ConcurrentHashMap with capacity 8 and load factor 0.6
ConcurrentHashMap<Key, Value> numbers = new ConcurrentHashMap<>(8, 0.6f);
En el código anterior, hemos creado un hashmap concurrente llamado numbers .
Aquí,
- Clave - un identificador único utilizado para asociar cada elemento (valor) en un mapa
- Valor - elementos asociados por claves en un mapa
Observe la parte new ConcurrentHashMap<>(8, 0.6)
. Aquí, el primer parámetro es capacidad y el segundo parámetro es loadFactor .
- capacidad - La capacidad de este mapa es 8. Es decir, puede almacenar 8 entradas.
- factor de carga - El factor de carga de este mapa es 0,6. Esto significa que, cada vez que nuestra tabla hash se llena en un 60 %, las entradas se mueven a una nueva tabla hash del doble del tamaño de la tabla hash original.
Capacidad predeterminada y factor de carga
Es posible crear un hashmap concurrente sin definir su capacidad y factor de carga. Por ejemplo,
// ConcurrentHashMap with default capacity and load factor
ConcurrentHashMap<Key, Value> numbers1 = new ConcurrentHashMap<>();
Por defecto,
- la capacidad del mapa será de 16
- el factor de carga será 0,75
Crear ConcurrentHashMap a partir de otros mapas
Así es como podemos crear un mapa hash concurrente que contenga todos los elementos de otros mapas.
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
class Main {
public static void main(String[] args) {
// Creating a hashmap of even numbers
HashMap<String, Integer> evenNumbers = new HashMap<>();
evenNumbers.put("Two", 2);
evenNumbers.put("Four", 4);
System.out.println("HashMap: " + evenNumbers);
// Creating a concurrent hashmap from other map
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>(evenNumbers);
numbers.put("Three", 3);
System.out.println("ConcurrentHashMap: " + numbers);
}
}
Salida
HashMap: {Four=4, Two=2} ConcurrentHashMap: {Four=4, Two=2, Three=3}
Métodos de ConcurrentHashMap
El ConcurrentHashMap
La clase proporciona métodos que nos permiten realizar varias operaciones en el mapa.
Insertar elementos en ConcurrentHashMap
put()
- inserta la asignación clave/valor especificada en el mapaputAll()
- inserta todas las entradas del mapa especificado a este mapaputIfAbsent()
- inserta la asignación clave/valor especificada en el mapa si la clave especificada no está presente en el mapa
Por ejemplo,
import java.util.concurrent.ConcurrentHashMap;
class Main {
public static void main(String[] args) {
// Creating ConcurrentHashMap of even numbers
ConcurrentHashMap<String, Integer> evenNumbers = new ConcurrentHashMap<>();
// Using put()
evenNumbers.put("Two", 2);
evenNumbers.put("Four", 4);
// Using putIfAbsent()
evenNumbers.putIfAbsent("Six", 6);
System.out.println("ConcurrentHashMap of even numbers: " + evenNumbers);
//Creating ConcurrentHashMap of numbers
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
numbers.put("One", 1);
// Using putAll()
numbers.putAll(evenNumbers);
System.out.println("ConcurrentHashMap of numbers: " + numbers);
}
}
Salida
ConcurrentHashMap of even numbers: {Six=6, Four=4, Two=2} ConcurrentHashMap of numbers: {Six=6, One=1, Four=-4, Two=2}
Acceso a elementos de mapas hash concurrentes
entrySet()
- devuelve un conjunto de todas las asignaciones de clave/valor del mapakeySet()
- devuelve un conjunto de todas las claves del mapavalues()
- devuelve un conjunto de todos los valores del mapa
Por ejemplo,
import java.util.concurrent.ConcurrentHashMap;
class Main {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
numbers.put("One", 1);
numbers.put("Two", 2);
numbers.put("Three", 3);
System.out.println("ConcurrentHashMap: " + numbers);
// Using entrySet()
System.out.println("Key/Value mappings: " + numbers.entrySet());
// Using keySet()
System.out.println("Keys: " + numbers.keySet());
// Using values()
System.out.println("Values: " + numbers.values());
}
}
Salida
ConcurrentHashMap: {One=1, Two=2, Three=3} Key/Value mappings: [One=1, Two=2, Three=3] Keys: [One, Two, Three] Values: [1, 2, 3]
get()
- Devuelve el valor asociado a la clave especificada. Devuelvenull
si no se encuentra la clave.getOrDefault()
- Devuelve el valor asociado a la clave especificada. Devuelve el valor predeterminado especificado si no se encuentra la clave.
Por ejemplo,
import java.util.concurrent.ConcurrentHashMap;
class Main {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
numbers.put("One", 1);
numbers.put("Two", 2);
numbers.put("Three", 3);
System.out.println("ConcurrentHashMap: " + numbers);
// Using get()
int value1 = numbers.get("Three");
System.out.println("Using get(): " + value1);
// Using getOrDefault()
int value2 = numbers.getOrDefault("Five", 5);
System.out.println("Using getOrDefault(): " + value2);
}
}
Salida
ConcurrentHashMap: {One=1, Two=2, Three=3} Using get(): 3 Using getOrDefault(): 5
Eliminar elementos de mapas hash concurrentes
remove(key)
- devuelve y elimina la entrada asociada con la clave especificada del maparemove(key, value)
- elimina la entrada del mapa solo si la clave especificada se asigna al valor especificado y devuelve un valor booleano
Por ejemplo,
import java.util.concurrent.ConcurrentHashMap;
class Main {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
numbers.put("One", 1);
numbers.put("Two", 2);
numbers.put("Three", 3);
System.out.println("ConcurrentHashMap: " + numbers);
// remove method with single parameter
int value = numbers.remove("Two");
System.out.println("Removed value: " + value);
// remove method with two parameters
boolean result = numbers.remove("Three", 3);
System.out.println("Is the entry {Three=3} removed? " + result);
System.out.println("Updated ConcurrentHashMap: " + numbers);
}
}
Salida
ConcurrentHashMap: {One=1, Two=2, Three=3} Removed value: 2 Is the entry {Three=3} removed? True Updated ConcurrentHashMap: {One=1}
Operaciones masivas de mapas hash simultáneos
El ConcurrentHashMap
class proporciona diferentes operaciones masivas que se pueden aplicar de forma segura a mapas simultáneos.
1. Método forEach()
El forEach()
itera sobre nuestras entradas y ejecuta la función especificada.
Incluye dos parámetros.
- Umbral de paralelismo - Especifica que después de cuantos elementos se ejecutan operaciones en un mapa en paralelo.
- transformador - Esto transformará los datos antes de que se pasen a la función especificada.
Por ejemplo,
import java.util.concurrent.ConcurrentHashMap;
class Main {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
numbers.put("One", 1);
numbers.put("Two", 2);
numbers.put("Three", 3);
System.out.println("ConcurrentHashMap: " + numbers);
// forEach() without transformer function
numbers.forEach(4, (k, v) -> System.out.println("key: " + k + " value: " + v));
// forEach() with transformer function
System.out.print("Values are ");
numbers.forEach(4, (k, v) -> v, (v) -> System.out.print(v + ", "));
}
}
Salida
ConcurrentHashMap: {One = 1, Two = 2, Three = 3} key: One value: 1 key: Two value: 2 key: Three value: 3 Values are 1, 2, 3,
En el programa anterior, hemos utilizado un umbral paralelo 4 . Esto significa que si el mapa contiene 4 entradas, la operación se ejecutará en paralelo.
Variación del método forEach()
forEachEntry()
- ejecuta la función especificada para cada entradaforEachKey()
- ejecuta la función especificada para cada teclaforEachValue()
- ejecuta la función especificada para cada valor
2. método de búsqueda()
El search()
El método busca en el mapa según la función especificada y devuelve la entrada coincidente.
Aquí, la función especificada determina qué entrada debe buscarse.
También incluye un parámetro opcional parallelThreshold . El umbral paralelo especifica que después de cuántos elementos en el mapa se ejecuta la operación en paralelo.
Por ejemplo,
import java.util.concurrent.ConcurrentHashMap;
class Main {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
numbers.put("One", 1);
numbers.put("Two", 2);
numbers.put("Three", 3);
System.out.println("ConcurrentHashMap: " + numbers);
// Using search()
String key = numbers.search(4, (k, v) -> {return v == 3 ? k: null;});
System.out.println("Searched value: " + key);
}
}
Salida
ConcurrentHashMap: {One=1, Two=2, Three=3} Searched value: Three
Variantes del método search()
searchEntries()
- la función de búsqueda se aplica a las asignaciones de clave/valorsearchKeys()
- la función de búsqueda solo se aplica a las teclassearchValues()
- la función de búsqueda solo se aplica a los valores
3. reducir() Método
El reduce()
El método acumula (reúne) cada entrada en un mapa. Esto se puede usar cuando necesitamos todas las entradas para realizar una tarea común, como sumar todos los valores de un mapa.
Incluye dos parámetros.
- Umbral de paralelismo - Especifica que después de cuántos elementos, las operaciones en un mapa se ejecutan en paralelo.
- transformador - Esto transformará los datos antes de que se pasen a la función especificada.
Por ejemplo,
import java.util.concurrent.ConcurrentHashMap;
class Main {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
numbers.put("One", 1);
numbers.put("Two", 2);
numbers.put("Three", 3);
System.out.println("ConcurrentHashMap: " + numbers);
// Using search()
int sum = numbers.reduce(4, (k, v) -> v, (v1, v2) -> v1 + v2);
System.out.println("Sum of all values: " + sum);
}
}
Salida
ConcurrentHashMap: {One=1, Two=2, Three=3} Sum of all values: 6
En el programa anterior, observe la declaración
numbers.reduce(4, (k, v) -> v, (v1, v2) -> v1+v2);
Aquí,
- 4 es un umbral paralelo
- (k, v) -> v es una función transformadora. Transfiere las asignaciones de clave/valor solo a valores.
- (v1, v2) -> v1+v2 es una función reductora. Reúne todos los valores y suma todos los valores.
Variantes del método reduce()
reduceEntries()
- devuelve el resultado de reunir todas las entradas usando la función reductora especificadareduceKeys()
- devuelve el resultado de reunir todas las claves utilizando la función reductora especificadareduceValues()
- devuelve el resultado de reunir todos los valores usando la función reductora especificada
ConcurrentHashMap vs HashMap
Estas son algunas de las diferencias entre ConcurrentHashMap
y HashMap,
ConcurrentHashMap
es un seguro para subprocesos recopilación. Es decir, varios subprocesos pueden acceder y modificarlo al mismo tiempo.ConcurrentHashMap
proporciona métodos para operaciones masivas comoforEach()
,search()
yreduce()
.
¿Por qué ConcurrentHashMap?
- El
ConcurrentHashMap
class permite que varios subprocesos accedan a sus entradas al mismo tiempo. - De forma predeterminada, el hashmap simultáneo se divide en 16 segmentos . Esta es la razón por la que se permite que 16 subprocesos modifiquen el mapa al mismo tiempo. Sin embargo, cualquier número de subprocesos puede acceder al mapa a la vez.
- El
putIfAbsent()
El método no anulará la entrada en el mapa si la clave especificada ya existe. - Proporciona su propia sincronización.
Java