Java中ConcurrentHashMap的实用场景:多变量并发下的价值疑问
Java中ConcurrentHashMap的适用场景疑问
请问Java中ConcurrentHashMap的适用场景是什么?当存在第二个变量时,操作需要加锁,这似乎抵消了它的优势。
假设有如下场景:
String foo; ConcurrentHashMap<String, String> bar;
访问bar无需加锁,但访问foo不行。如果需要同时操作foo和bar才能完成有效工作,那ConcurrentHashMap的实用场景是什么?此时既然已经加锁,使用普通HashMap不也可以吗?
我很难想到在高并发临界区中只需要单个ConcurrentHashMap变量的场景。
以下是示例代码,该代码有时输出199,有时输出200,但ConcurrentHashMap始终能保证正确性:
import java.util.concurrent.ConcurrentHashMap; class MyClass { private ConcurrentHashMap<Integer, String> map = new ConcurrentHashMap<>(); private int myInt = 0; public void addToMap(int key, String value) { map.put(key, value); } public void incrementInt() { myInt++; } public void runThreads() { Thread t1 = new Thread(() -> { for (int i = 0; i < 100; i++) { addToMap(i, "Thread 1 - " + i); incrementInt(); } }); Thread t2 = new Thread(() -> { for (int i = 100; i < 200; i++) { addToMap(i, "Thread 2 - " + i); incrementInt(); } }); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("myInt = " + myInt); } public static void main(String[] args) { MyClass myClass = new MyClass(); myClass.runThreads(); } }
核心解答
1. ConcurrentHashMap的核心适用场景
它最适合高并发环境下仅对哈希表本身进行独立操作的场景:
- 比如多线程独立读写不同key的缓存(如用户会话存储、配置项缓存),此时每个线程的操作基本不涉及其他共享变量,完全不需要额外加锁。
- 或者业务逻辑中,对哈希表的操作是独立的原子性需求,不需要和其他变量关联(比如统计不同请求类型的次数,仅用ConcurrentHashMap的
compute或merge方法完成原子更新)。
2. 关于多变量场景的误区
当需要同时操作foo和bar时,确实需要额外加锁来保证两者的一致性,但这不代表ConcurrentHashMap没用:
- 加锁粒度更小:如果用普通HashMap,你需要给整个HashMap加锁,而ConcurrentHashMap本身的CAS+分段锁机制(Java 8+实现)已经保证了哈希表内部的线程安全,此时外部加锁只是为了协调
foo和bar的关系,哈希表内部的并发效率依然比普通HashMap+全局锁更高。 - 避免额外线程安全问题:即使加了外部锁,ConcurrentHashMap依然能防止其他未走这个加锁逻辑的线程对哈希表的非法操作(比如其他地方单独访问
bar时,不需要再重复加锁)。
3. 示例代码的问题点
示例中myInt++不是原子操作,所以才会出现199的情况,但map的操作始终正确——这正好体现了ConcurrentHashMap的价值:它保证了自身操作的线程安全,不需要你为它额外操心。如果换成普通HashMap,即使myInt的问题解决了,map也会出现并发修改异常或者数据丢失。
内容的提问来源于stack exchange,提问作者Gavin Ray
相关产品推荐
相关产品推荐

