在多线程编程中,HashMap是非线程安全的,而Hashtable虽然是线程安全的,但性能较差。ConcurrentHashMap应运而生,它提供了更好的并发性能和线程安全性。本文将详细介绍ConcurrentHashMap的使用方法。
ConcurrentHashMap是Java并发包(java.util.concurrent)中的一个线程安全的HashMap实现。与Hashtable不同,它使用分段锁(Java 7)或CAS操作(Java 8+)来实现更高的并发性能。
javaimport java.util.concurrent.ConcurrentHashMap;
// 创建空的ConcurrentHashMap
ConcurrentHashMap<String, Integer> map1 = new ConcurrentHashMap<>();
// 创建指定初始容量的ConcurrentHashMap
ConcurrentHashMap<String, Integer> map2 = new ConcurrentHashMap<>(32);
// 从现有Map创建
Map<String, Integer> existingMap = new HashMap<>();
existingMap.put("A", 1);
existingMap.put("B", 2);
ConcurrentHashMap<String, Integer> map3 = new ConcurrentHashMap<>(existingMap);
// 创建指定初始容量和负载因子的ConcurrentHashMap
ConcurrentHashMap<String, Integer> map4 = new ConcurrentHashMap<>(16, 0.75f);
// 创建指定初始容量、负载因子和并发级别的ConcurrentHashMap
ConcurrentHashMap<String, Integer> map5 = new ConcurrentHashMap<>(16, 0.75f, 8);
javaConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
// 添加元素
concurrentMap.put("apple", 10);
concurrentMap.put("banana", 20);
concurrentMap.put("orange", 15);
// 如果键不存在则添加
concurrentMap.putIfAbsent("apple", 50); // 不会执行,因为"apple"已存在
concurrentMap.putIfAbsent("grape", 30); // 会添加,因为"grape"不存在
// 获取元素
Integer apples = concurrentMap.get("apple"); // 返回10
Integer unknown = concurrentMap.get("unknown"); // 返回null
// 检查键是否存在
boolean hasApple = concurrentMap.containsKey("apple"); // true
boolean hasMango = concurrentMap.containsKey("mango"); // false
// 删除元素
concurrentMap.remove("banana"); // 删除键为"banana"的条目
concurrentMap.remove("orange", 10); // 只有当键为"orange"且值为10时才删除
// 获取大小
int size = concurrentMap.size();
// 检查是否为空
boolean isEmpty = concurrentMap.isEmpty();
javaConcurrentHashMap<String, Integer> inventory = new ConcurrentHashMap<>();
inventory.put("widget", 100);
// compute方法:根据现有键值对计算新值
inventory.compute("widget", (key, value) -> value == null ? 1 : value + 50);
// 现在widget的值为150
// computeIfAbsent:如果键不存在,计算新值
inventory.computeIfAbsent("gadget", key -> 200);
// gadget不存在,所以设置为200
// computeIfPresent:如果键存在,计算新值
inventory.computeIfPresent("widget", (key, value) -> value - 10);
// widget存在,所以值变为140
// merge方法:合并值
inventory.merge("widget", 50, (oldValue, newValue) -> oldValue + newValue);
// widget的值变为190 (140 + 50)
javaConcurrentHashMap<String, String> userSessions = new ConcurrentHashMap<>();
userSessions.put("user1", "session1");
userSessions.put("user2", "session2");
userSessions.put("user3", "session3");
// forEach:遍历所有条目
userSessions.forEach((key, value) ->
System.out.println("User: " + key + ", Session: " + value));
// forEach带并行阈值
userSessions.forEach(2, (key, value) ->
System.out.println("Processing: " + key));
// reduce:归约操作
ConcurrentHashMap<String, Integer> scores = new ConcurrentHashMap<>();
scores.put("Alice", 85);
scores.put("Bob", 92);
scores.put("Charlie", 78);
int totalScore = scores.reduce(2, (key, value) -> value, Integer::sum);
System.out.println("Total score: " + totalScore);
// search:搜索操作
String found = scores.search(2, (key, value) -> value > 90 ? key : null);
System.out.println("Score > 90: " + found); // 输出: Bob
javapublic class ConcurrentHashMapExample {
private final ConcurrentHashMap<String, AtomicInteger> counterMap =
new ConcurrentHashMap<>();
// 线程安全的计数方法
public void increment(String key) {
counterMap.compute(key, (k, v) -> {
if (v == null) {
return new AtomicInteger(1);
} else {
v.incrementAndGet();
return v;
}
});
}
// 或者使用更简洁的方式
public void incrementBetter(String key) {
counterMap.computeIfAbsent(key, k -> new AtomicInteger(0)).incrementAndGet();
}
public int getCount(String key) {
AtomicInteger counter = counterMap.get(key);
return counter == null ? 0 : counter.get();
}
}
javapublic class SimpleCache<K, V> {
private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<>();
private final long defaultExpiry;
public SimpleCache(long defaultExpiryMillis) {
this.defaultExpiry = defaultExpiryMillis;
}
public V get(K key) {
return cache.get(key);
}
public void put(K key, V value) {
cache.put(key, value);
}
public V getOrCompute(K key, Supplier<V> supplier) {
return cache.computeIfAbsent(key, k -> supplier.get());
}
public boolean remove(K key) {
return cache.remove(key) != null;
}
public void clear() {
cache.clear();
}
}
javapublic class MapComparison {
public static void main(String[] args) throws InterruptedException {
// 测试HashMap(非线程安全)
Map<String, Integer> hashMap = new HashMap<>();
testMapPerformance(hashMap, "HashMap");
// 测试Hashtable(线程安全,但性能较差)
Map<String, Integer> hashtable = new Hashtable<>();
testMapPerformance(hashtable, "Hashtable");
// 测试ConcurrentHashMap(线程安全,高性能)
Map<String, Integer> concurrentHashMap = new ConcurrentHashMap<>();
testMapPerformance(concurrentHashMap, "ConcurrentHashMap");
}
private static void testMapPerformance(Map<String, Integer> map, String mapType)
throws InterruptedException {
int threadCount = 10;
int operationsPerThread = 10000;
Thread[] threads = new Thread[threadCount];
long startTime = System.currentTimeMillis();
for (int i = 0; i < threadCount; i++) {
final int threadId = i;
threads[i] = new Thread(() -> {
for (int j = 0; j < operationsPerThread; j++) {
String key = "key-" + threadId + "-" + j;
map.put(key, j);
map.get(key);
}
});
threads[i].start();
}
for (Thread thread : threads) {
thread.join();
}
long endTime = System.currentTimeMillis();
System.out.println(mapType + " 耗时: " + (endTime - startTime) + "ms");
}
}
java// 如果知道大概的元素数量,设置合适的初始容量可以提高性能
int expectedSize = 100000;
ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>(
(int)(expectedSize / 0.75f) + 1
);
java// 根据预期的并发线程数设置并发级别
int expectedThreads = 16;
ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>(
16, 0.75f, expectedThreads
);
javaConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
// 安全的遍历方式
for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
// 在遍历过程中可以安全地修改值,但不能添加/删除键
map.put(key, map.get(key) + 1); // 安全
// map.remove(key); // 可能导致未定义行为
}
java// 不安全的做法
if (!map.containsKey(key)) {
map.put(key, value); // 这不是原子操作!
}
// 安全的做法
map.putIfAbsent(key, value);
// 或者使用computeIfAbsent
map.computeIfAbsent(key, k -> createExpensiveValue(k));
java// 错误用法:check-then-act模式
if (concurrentMap.containsKey(key)) {
// 在这期间,其他线程可能已经删除了该键
Value value = concurrentMap.get(key); // 可能返回null
process(value); // 可能抛出NullPointerException
}
// 正确用法:原子操作
Value value = concurrentMap.get(key);
if (value != null) {
process(value);
}
javaConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("A", 1);
map.put("B", 2);
Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, Integer> entry = iterator.next();
System.out.println(entry.getKey() + ": " + entry.getValue());
// 其他线程在此期间修改map不会影响当前迭代
// 但也不会在迭代器中反映这些变化
}
ConcurrentHashMap是Java并发编程中的重要工具,它提供了:
在使用时需要注意:
通过合理使用ConcurrentHashMap,可以构建出高性能、线程安全的并发应用程序。
本文作者:zjx171
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!