Java ConcurrentHashMap的clear方法默认行为与线程安全问询
关于ConcurrentHashMap的clear()方法及线程安全场景分析
嘿,咱们来一步步拆解你关于ConcurrentHashMap clear()的问题哈,这些细节确实容易搞混~
1. ConcurrentHashMap.clear()的默认行为
在JDK 8及以后的版本里,ConcurrentHashMap.clear()是非阻塞、按哈希桶分段清理的操作,核心逻辑是这样的:
- 它会逐个遍历Map里的每个哈希桶(bucket),先尝试用CAS操作把当前桶的头节点直接置为null;
- 如果CAS失败(说明有其他线程正在改这个桶),就用
synchronized锁定这个桶的头节点,再把桶里的所有链表/红黑树节点都清掉; - 整个过程不会把整个Map锁死,只会对正在处理的桶做局部同步,其他线程该访问其他桶还是能正常访问,兼顾了线程安全和并发性能。
不过要注意,它是弱一致性的——意思就是在clear执行的过程中,其他线程可能会看到有些元素还在,有些已经没了,但绝对不会出现数据乱掉的情况。
2. 会不会锁定所有条目并标记待删除键?
完全不会哈:
- clear()不会一次性把所有条目都锁住,只会锁当前正在处理的那个哈希桶,处理完一个就放掉,再处理下一个;
- 它也没有什么“标记待删除键”的逻辑,就是直接把节点置为null来清理,不存在中间的待删除状态。
3. 要不要额外用synchronized包裹clear()?
真的没必要!ConcurrentHashMap本身所有公开方法(包括clear())都是线程安全的,你额外加个synchronized反而会拖垮性能——相当于把原本的分段同步变成了全局锁,直接废掉了ConcurrentHashMap的并发优势。
4. 你说的那个场景:最终结果是{}还是{1:0}?
这个结果没法定死,完全看两个线程的执行顺序:
- 如果Thread2的
compute(1, ...)在Thread1清理key=1所在的桶之前跑起来:
这时候key=1的节点还在,lambda里的v是1,所以会算出1+1=2并更新到Map里。等Thread1清理到这个桶的时候,会把整个桶的节点都清成null,最后Map就是空的{}。 - 如果Thread2的compute()是在Thread1清理key=1的桶的过程中或者之后执行:
Thread1清理的时候会锁住key=1的桶,Thread2的compute会被卡住,等Thread1清完才继续。这时候compute看到v是null,就会返回0并存进去,最后Map就是{1:0}。
因为clear()是弱一致性操作,没有全局锁保证整个清理过程是原子的,所以这两种结果都有可能出现哦。
内容的提问来源于stack exchange,提问作者J L
相关产品推荐
相关产品推荐

