Java ConcurrentHashMap
ConcurrentHashMap 实现了一个线程安全且保证原子操作的高性能的 Map。在本教程中,我们将通过示例介绍 Java ConcurrentHashMap 类和它的用法。
在本教程中,我们将通过示例介绍 Java ConcurrentHashMap 类和它的用法。
ConcurrentHashMap
实现了一个线程安全且保证原子操作的高性能的 Map。ConcurrentHashMap
实现了 ConcurrentMap
接口,适用于多线程并发环境。
创建 ConcurrentHashMap
我们导入 java.util.ConcurrentHashMap
类后,就可以通过构造方法创建 ConcurrentHashMap
对象了。
ConcurrentHashMap<Key, Value> numbers = new ConcurrentHashMap<>();
ConcurrentHashMap
的底层实现和 HashMap
相似,只是通过 CAS 操作和枷锁机制实现多线程下的安全操作。
因此,ConcurrentHashMap
的构造方法也支持传入初始容量和负载因子,如下:
ConcurrentHashMap(int initialCapacity, float loadFactor)
关于初始容量和负载因子参数的更多介绍请查看 Java HashMap 类。
从其他 Map 创建 ConcurrentHashMap
下面示例展示了如何使用构造方法 ConcurrentHashMap(Map<? extends K, ? extends V> m)
将其他的 Map
对象转为 ConcurrentHashMap。
import java.util.concurrent.ConcurrentHashMap;
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
HashMap<String, Integer> evenNumbers = new HashMap<>();
evenNumbers.put("Two", 2);
evenNumbers.put("Four", 4);
System.out.println("HashMap: " + evenNumbers);
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>(evenNumbers);
numbers.put("Three", 3);
System.out.println("ConcurrentHashMap: " + numbers);
}
}
输出
HashMap: {Four=4, Two=2}
ConcurrentHashMap: {Four=4, Two=2, Three=3}
ConcurrentHashMap 的方法
ConcurrentHashMap
类实现了 ConcurrentHashMap
接口和 Map
接口定义的全部的方法。我们看一下常用的操作:
向 ConcurrentHashMap 插入元素
put()
- 将指定的键值对条目插入到 Map 中putAll()
- 将指定 Map 中的所有条目插入到 Map 中putIfAbsent()
- 如果 Map 中不存在指定的键,则将指定的键值对条目插入到 Map 中
例如,
import java.util.concurrent.ConcurrentHashMap;
public class Main {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> evenNumbers = new ConcurrentHashMap<>();
// put()
evenNumbers.put("Two", 2);
evenNumbers.put("Four", 4);
// putIfAbsent()
evenNumbers.putIfAbsent("Six", 6);
System.out.println("ConcurrentHashMap of even numbers: " + evenNumbers);
ConcurrentHashMap<String, Integer> numbers = new ConcurrentHashMap<>();
numbers.put("One", 1);
// putAll()
numbers.putAll(evenNumbers);
System.out.println("ConcurrentHashMap of numbers: " + numbers);
}
}
输出
ConcurrentHashMap of even numbers: {Six=6, Four=4, Two=2}
ConcurrentHashMap of numbers: {Six=6, One=1, Four=4, Two=2}
entrySet()、keySet() 和 values()
entrySet()
- 返回 Map 的所有键值对条目的 Set 集合keySet()
- 返回 Map 的所有键的 Set 集合values()
- 返回 Map 的所有值的集合
例如,
import java.util.concurrent.ConcurrentHashMap;
public 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());
}
}
输出
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() 和 getOrDefault()
get()
- 返回与指定键关联的值。如果未找指定键,则返回null
。getOrDefault()
- 返回与指定键关联的值。如果未找到该键,则返回指定的默认值。
例如,
import java.util.concurrent.ConcurrentHashMap;
public 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);
// get()
int value1 = numbers.get("Three");
System.out.println("Using get(): " + value1);
// getOrDefault()
int value2 = numbers.getOrDefault("Five", 5);
System.out.println("Using getOrDefault(): " + value2);
}
}
输出
ConcurrentHashMap: {One=1, Two=2, Three=3}
Using get(): 3
Using getOrDefault(): 5
删除 ConcurrentHashMap 元素
remove(key)
- 删除并返回与指定键关联的条目remove(key, value)
- 删除与指定键和指定值匹配的条目,成功返回true
,否则返回false
。
例如,
import java.util.concurrent.ConcurrentHashMap;
public 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);
int value = numbers.remove("Two");
System.out.println("Removed value: " + value);
boolean result = numbers.remove("Three", 3);
System.out.println("Is the entry {Three=3} removed? " + result);
System.out.println("Updated ConcurrentHashMap: " + numbers);
}
}
输出
ConcurrentHashMap: {One=1, Two=2, Three=3}
Removed value: 2
Is the entry {Three=3} removed? true
Updated ConcurrentHashMap: {One=1}
ConcurrentHashMap 并行操作
ConcurrentHashMap
类提供了几个线程安全的方法可进行并行批量操作。
forEach() 方法
forEach()
方法可以并发迭代我们的条目并执行指定的操作。它有 2 个重载方法:
forEach(parallelismThreshold, transformer, action)
forEach(parallelismThreshold, action)
以下是参数说明:
parallelismThreshold
- 并行阈值,迭代元素的并发数。transformer
: 转换方法。对键和值执行转换操作,并返回一个值。action
: 操作方法。当存在transformer
时,action 需要一个参数为转换方法的返回值;当不存在transformer
时,action 需要两个参数:键和值。
例如,
import java.util.concurrent.ConcurrentHashMap;
public 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);
// transformer
numbers.forEach(4, (k, v) -> System.out.println("key: " + k + " value: " + v));
// no transformer
System.out.print("Values are ");
numbers.forEach(4, (k, v) -> v, (v) -> System.out.print(v + ", "));
}
}
输出
ConcurrentHashMap: {One=1, Two=2, Three=3}
key: One value: 1
key: Two value: 2
key: Three value: 3
Values are 1, 2, 3,
在上面的程序中,我们使用了并行阈值 4
。这意味这同时最多有 4 个元素被并行处理。
forEach() 方法的变体
forEachEntry()
- 为每个 Entry 条目执行指定的操作forEachKey()
- 为每个键执行指定的操作forEachValue()
- 为每个值执行指定的操作
2.search()方法
search(parallelismThreshold, searchFunction)
逐个对每个键值对执行执行的搜索函数,直到搜索函数返回一个非 null
的结果,然后返回此结果,否则就返回 null
。
以下是参数说明:
parallelismThreshold
- 并行阈值,迭代元素的并发数。searchFunction
- 搜索函数,返回非 null 值为搜索成功。
例如,
import java.util.concurrent.ConcurrentHashMap;
public 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) -> v == 3 ? k : null);
System.out.println("Searched value: " + key);
}
}
输出
ConcurrentHashMap: {One=1, Two=2, Three=3}
Searched value: Three
search() 方法的变体
searchEntries()
- 搜索功能应每个 Entry 条目searchKeys()
- 仅搜索键searchValues()
- 仅搜索值
3.reduce()方法
reduce(parallelismThreshold, transformer, reducer)
先对每个键值对执行指定的转换函数,并使用 reducer
累加所有转换的结果。
以下是参数说明:
parallelismThreshold
- 并行阈值,迭代元素的并发数。transformer
: 转换方法。对键和值执行转换操作,并返回一个值。reducer
: 累计方法
例如,
import java.util.concurrent.ConcurrentHashMap;
public 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 reduce()
int sum = numbers.reduce(4, (k, v) -> v, (v1, v2) -> v1 + v2);
System.out.println("Sum of all values: " + sum);
}
}
输出
ConcurrentHashMap: {One=1, Two=2, Three=3}
Sum of all values: 6
在上面的程序中,注意以下语句:
numbers.reduce(4, (k, v) -> v, (v1, v2) -> v1+v2);
这里,
4
是并行阈值(k, v) -> v
是 lambda 表达式的转换函数,只返回了键值对中的值。(v1, v2) -> v1 + v2
是一个 reducer 函数,它将所有值收集在一起并累加。
reduce() 方法的变体
reduceEntries()
- 对所有的 Entry 对象执行 reduce 操作reduceKeys()
- 对所有的键执行 reduce 操作reduceValues()
- 对所有的值执行 reduce 操作
ConcurrentHashMap 与 HashMap
以下是 ConcurrentHashMap
和 HashMap
之间的一些差异,
ConcurrentHashMap
是一个线程安全的集合,即多个线程可以同时访问和修改它,但不会有线程安全问题。ConcurrentHashMap
提供了可并发批量操作的方法,如forEach()
、search()
和reduce()
。- 在多线程环境下,
ConcurrentHashMap
是高性能的。