Java ConcurrentHashMap
Java ConcurrentHashMap
In diesem Tutorial lernen wir die Java ConcurrentHashMap-Klasse und ihre Operationen anhand von Beispielen kennen.
Der ConcurrentHashMap
-Klasse des Java Collections Framework stellt eine Thread-sichere Zuordnung bereit. Das heißt, mehrere Threads können gleichzeitig auf die Map zugreifen, ohne die Konsistenz der Einträge in einer Map zu beeinträchtigen.
Es implementiert die ConcurrentMap-Schnittstelle.
Eine ConcurrentHashMap erstellen
Um eine gleichzeitige Hashmap zu erstellen, müssen wir den java.util.concurrent.ConcurrentHashMap
importieren Paket zuerst. Sobald wir das Paket importiert haben, können wir wie folgt gleichzeitige Hashmaps in Java erstellen.
// ConcurrentHashMap with capacity 8 and load factor 0.6
ConcurrentHashMap<Key, Value> numbers = new ConcurrentHashMap<>(8, 0.6f);
Im obigen Code haben wir eine gleichzeitige Hashmap namens numbers erstellt .
Hier,
- Schlüssel - eine eindeutige Kennung, die verwendet wird, um jedes Element (Wert) in einer Zuordnung zuzuordnen
- Wert - Elemente, die durch Schlüssel in einer Karte verknüpft sind
Beachten Sie den Teil new ConcurrentHashMap<>(8, 0.6)
. Hier ist der erste Parameter Kapazität und der zweite Parameter ist loadFactor .
- Kapazität - Die Kapazität dieser Karte beträgt 8. Das heißt, sie kann 8 Einträge speichern.
- loadFactor - Der Ladefaktor dieser Karte beträgt 0,6. Das heißt, immer wenn unsere Hash-Tabelle zu 60 % gefüllt ist, werden die Einträge in eine neue Hash-Tabelle verschoben, die doppelt so groß ist wie die ursprüngliche Hash-Tabelle.
Standardkapazität und Ladefaktor
Es ist möglich, eine gleichzeitige Hashmap zu erstellen, ohne deren Kapazität und Lastfaktor zu definieren. Zum Beispiel
// ConcurrentHashMap with default capacity and load factor
ConcurrentHashMap<Key, Value> numbers1 = new ConcurrentHashMap<>();
Standardmäßig
- Die Kapazität der Karte beträgt 16
- der Ladefaktor beträgt 0,75
ConcurrentHashMap aus anderen Maps erstellen
So können wir eine gleichzeitige Hashmap erstellen, die alle Elemente anderer Maps enthält.
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);
}
}
Ausgabe
HashMap: {Four=4, Two=2} ConcurrentHashMap: {Four=4, Two=2, Three=3}
Methoden von ConcurrentHashMap
Die ConcurrentHashMap
Die Klasse stellt Methoden bereit, mit denen wir verschiedene Operationen auf der Karte ausführen können.
Elemente in ConcurrentHashMap einfügen
put()
- fügt die angegebene Schlüssel/Wert-Zuordnung in die Zuordnung einputAll()
- fügt alle Einträge aus der angegebenen Map in diese Map einputIfAbsent()
- fügt die angegebene Schlüssel/Wert-Zuordnung in die Map ein, wenn der angegebene Schlüssel nicht in der Map vorhanden ist
Zum Beispiel
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);
}
}
Ausgabe
ConcurrentHashMap of even numbers: {Six=6, Four=4, Two=2} ConcurrentHashMap of numbers: {Six=6, One=1, Four=-4, Two=2}
Zugriff auf ConcurrentHashMap-Elemente
1. Mit entrySet(), keySet() und values()
entrySet()
- gibt einen Satz aller Schlüssel/Wert-Mappings der Map zurückkeySet()
- gibt einen Satz aller Schlüssel der Karte zurückvalues()
- gibt einen Satz aller Werte der Karte zurück
Zum Beispiel
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());
}
}
Ausgabe
ConcurrentHashMap: {One=1, Two=2, Three=3} Key/Value mappings: [One=1, Two=2, Three=3] Keys: [One, Two, Three] Values: [1, 2, 3]
2. Verwendung von get() und getOrDefault()
get()
- Gibt den Wert zurück, der dem angegebenen Schlüssel zugeordnet ist. Gibtnull
zurück wenn der Schlüssel nicht gefunden wird.getOrDefault()
- Gibt den Wert zurück, der dem angegebenen Schlüssel zugeordnet ist. Gibt den angegebenen Standardwert zurück, wenn der Schlüssel nicht gefunden wird.
Zum Beispiel
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);
}
}
Ausgabe
ConcurrentHashMap: {One=1, Two=2, Three=3} Using get(): 3 Using getOrDefault(): 5
ConcurrentHashMap-Elemente entfernen
remove(key)
- gibt den mit dem angegebenen Schlüssel verknüpften Eintrag aus der Map zurück und entfernt ihnremove(key, value)
- Entfernt den Eintrag nur dann aus der Zuordnung, wenn der angegebene Schlüssel dem angegebenen Wert zugeordnet ist, und gibt einen booleschen Wert zurück
Zum Beispiel
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);
}
}
Ausgabe
ConcurrentHashMap: {One=1, Two=2, Three=3} Removed value: 2 Is the entry {Three=3} removed? True Updated ConcurrentHashMap: {One=1}
Mehrere gleichzeitige HashMap-Operationen
Die ConcurrentHashMap
-Klasse bietet verschiedene Massenoperationen, die sicher auf gleichzeitige Karten angewendet werden können.
1. forEach()-Methode
Die forEach()
Methode iteriert über unsere Einträge und führt die angegebene Funktion aus.
Es enthält zwei Parameter.
- parallelismThreshold - Es gibt an, nach wie vielen Elementen Operationen in einer Map parallel ausgeführt werden.
- Transformator - Dadurch werden die Daten transformiert, bevor die Daten an die angegebene Funktion übergeben werden.
Zum Beispiel
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 + ", "));
}
}
Ausgabe
ConcurrentHashMap: {One = 1, Two = 2, Three = 3} key: One value: 1 key: Two value: 2 key: Three value: 3 Values are 1, 2, 3,
Im obigen Programm haben wir den parallelen Schwellenwert 4 verwendet . Das bedeutet, wenn die Karte 4 Einträge enthält, wird die Operation parallel ausgeführt.
Variation der forEach()-Methode
forEachEntry()
- führt die angegebene Funktion für jeden Eintrag ausforEachKey()
- führt die angegebene Funktion für jede Taste ausforEachValue()
- führt die angegebene Funktion für jeden Wert aus
2. search()-Methode
Der search()
-Methode durchsucht die Karte basierend auf der angegebenen Funktion und gibt den übereinstimmenden Eintrag zurück.
Hier bestimmt die angegebene Funktion, welcher Eintrag gesucht werden soll.
Es enthält auch einen optionalen Parameter parallelThreshold . Der parallele Schwellenwert gibt an, nach wie vielen Elementen in der Karte die Operation parallel ausgeführt wird.
Zum Beispiel
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);
}
}
Ausgabe
ConcurrentHashMap: {One=1, Two=2, Three=3} Searched value: Three
Varianten der Methode search()
searchEntries()
- Suchfunktion wird auf Schlüssel/Wert-Zuordnungen angewendetsearchKeys()
- Suchfunktion wird nur auf die Tasten angewendetsearchValues()
- Suchfunktion wird nur auf die Werte angewendet
3. Reduce()-Methode
Die reduce()
-Methode akkumuliert (sammelt) jeden Eintrag in einer Map. Dies kann verwendet werden, wenn wir alle Einträge benötigen, um eine gemeinsame Aufgabe auszuführen, wie das Hinzufügen aller Werte einer Karte.
Es enthält zwei Parameter.
- parallelismThreshold - Es gibt an, nach wie vielen Elementen Operationen in einer Map parallel ausgeführt werden.
- Transformator - Dadurch werden die Daten transformiert, bevor die Daten an die angegebene Funktion übergeben werden.
Zum Beispiel
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);
}
}
Ausgabe
ConcurrentHashMap: {One=1, Two=2, Three=3} Sum of all values: 6
Beachten Sie im obigen Programm die Anweisung
numbers.reduce(4, (k, v) -> v, (v1, v2) -> v1+v2);
Hier,
- 4 ist ein paralleler Schwellenwert
- (k, v) -> v ist eine Transformatorfunktion. Es überträgt die Schlüssel/Wert-Zuordnungen nur in Werte.
- (v1, v2) -> v1+v2 ist eine Reduktionsfunktion. Es sammelt alle Werte und addiert alle Werte.
Varianten der Reduce()-Methode
reduceEntries()
- gibt das Ergebnis des Sammelns aller Einträge mit der angegebenen Reducer-Funktion zurückreduceKeys()
- gibt das Ergebnis des Sammelns aller Schlüssel mit der angegebenen Reducer-Funktion zurückreduceValues()
- gibt das Ergebnis des Sammelns aller Werte mit der angegebenen Reducer-Funktion zurück
ConcurrentHashMap vs. HashMap
Hier sind einige der Unterschiede zwischen ConcurrentHashMap
und HashMap,
ConcurrentHashMap
ist threadsicher Sammlung. Das heißt, mehrere Threads können gleichzeitig darauf zugreifen und es ändern.ConcurrentHashMap
bietet Methoden für Massenoperationen wieforEach()
,search()
undreduce()
.
Warum ConcurrentHashMap?
- Der
ConcurrentHashMap
-Klasse erlaubt mehreren Threads den gleichzeitigen Zugriff auf ihre Einträge. - Standardmäßig ist die gleichzeitige Hashmap in 16 Segmente unterteilt . Aus diesem Grund dürfen 16 Threads gleichzeitig die Karte modifizieren. Es können jedoch beliebig viele Threads gleichzeitig auf die Karte zugreifen.
- Der
putIfAbsent()
-Methode überschreibt den Eintrag in der Zuordnung nicht, wenn der angegebene Schlüssel bereits vorhanden ist. - Es bietet seine eigene Synchronisation.
Java