ConcurrentHashMap 并非完全线程安全,单个方法调用(如 put、get、remove、computeIfAbsent、merge)原子,但复合操作需额外同步;size() 返回近似值,keySet().iterator() 为弱一致性迭代器。
ConcurrentHashMap 真的完全线程安全吗?
它不是“所有操作都加全局锁”的线程安全,而是通过分段锁(JDK 7)或 CAS + synchronized(JDK 8+)实现**部分操作的线程安全**。关键在于:单个方法调用是原子的,但复合操作(如
)仍需额外同步。
哪些操作是原子的?哪些不是?
以下方法在 JDK 8+ 中保证单次调用的原子性:
、
、
、
、
。但这些不是:
返回的是近似值(可能滞后),高并发下不建议用于条件判断
返回的迭代器是弱一致性(weakly consistent),可遍历到已删除元素,也可能跳过刚插入元素
同样基于弱一致性迭代器,不保证看到全部实时变更
为什么不能用 ConcurrentHashMap 替代 synchronized 块?
常见误用是把
当作“免同步万能容器”。例如:
这仍是竞态条件:两个线程同时通过
检查,都会执行
并写入。正确写法是:
Eclipse导入Android或其他的JAVA项目的正确方法 WORD版
本文档主要讲述的是Eclipse导入Android或其他的JAVA项目的正确方法;希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
下载
立即学习
“
Java免费学习笔记(深入)
”;
该方法内部用 CAS 或细粒度锁确保只计算一次。其他类似场景也应优先使用
、
等原子更新方法。
JDK 7 和 JDK 8+ 的底层差异影响什么?
升级后行为变化容易被忽略:
JDK 7 使用
数组分段加锁,
影响初始化桶数,但实际并发度由哈希分布决定
JDK 8+ 废除
,改用
数组 + 链表/红黑树,锁粒度细化到单个
(即数组槽位)
在 JDK 8+ 中对空槽位用 CAS,非空时再加
锁住首节点;这意味着高冲突哈希可能导致局部锁争用
在 JDK 8+ 中通过累加每个桶的修改计数(
)估算,但不保证强一致
多线程下真正麻烦的从来不是单个
,而是你写的那几行看似“顺手”的 if-else 逻辑。
if (map.get(k) == null) map.put(k, v)putgetremovecomputeIfAbsentmergesize()keySet().iterator()for (Entry e : map.entrySet())ConcurrentHashMapif (!map.containsKey(key)) {
map.put(key, expensiveCompute());
}containsKeyexpensiveCompute()map.computeIfAbsent(key, k -> expensiveCompute());computeIfPresentmergeSegmentconcurrencyLevelSegmentNodeNodeputsynchronizedsize()baseCount + sum of counterCellsput