ConcurrentHashMap 没有 forEachKey() 方法,只有 forEachKey(long parallelismThreshold, Consumer

ConcurrentHashMap 没有名为 forEachKey 的方法。
这是个常见误解。Java 标准库中的 ConcurrentHashMap 不提供 forEachKey 方法,它提供的是:
-
forEachKey(long parallelismThreshold, Consumer super K> action)—— 这是 并行遍历所有键 的正确方法(JDK 8+) - 类似还有
forEachValue、forEach(键值对)、forEachEntry
✅ 正确用法如下:
使用 forEachKey 并行遍历键
该方法会根据当前 Map 的大小和指定的 parallelismThreshold(并行阈值),自动决定是否拆分任务并行执行。当 map 元素数量 ≥ threshold 时,内部使用 ForkJoinPool 并行处理;否则退化为串行遍历。
示例:
ConcurrentHashMap<string integer> map = new ConcurrentHashMap();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
<p>// 并行遍历所有键:阈值设为 1(通常可设为 1 或更小以确保并行)
map.forEachKey(1, key -> {
System.out.println(Thread.currentThread().getName() + " -> " + key);
});
</p></string>
parallelismThreshold 怎么选?
这个参数不是线程数,而是「任务拆分的最小规模」。一般建议:
- 设为 1:强制尽可能并行(适合键数量较多且操作较重的场景)
- 设为 Map.size() / (ForkJoinPool.getCommonPoolParallelism() * 2):粗略平衡负载
- 设为 Integer.MAX_VALUE:等价于串行遍历(不推荐,除非调试)
注意线程安全与副作用
虽然遍历本身是弱一致性的(不会抛 ConcurrentModificationException),但:
- 遍历过程中允许修改 map(增删改),但不能保证看到最新修改
- action 函数必须是无状态、线程安全的,避免共享可变变量
- 不要在 action 中调用 map 的结构性修改方法(如 put/remove),可能引发不可预期行为
替代方案:用 keySet().parallelStream()
如果想更灵活地控制并行逻辑,也可以:
map.keySet().parallelStream()
.forEach(key -> System.out.println(key));
⚠️ 注意:keySet().parallelStream() 底层仍基于 same ForkJoinPool,但语义更直观;不过它不保证遍历顺序,也不保证弱一致性语义完全等同于 forEachKey(比如对实时修改的可见性略有差异)。
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











