Collectors.toConcurrentMap能保证线程安全,因其使用ConcurrentHashMap并采用分段原子操作(如merge、putIfAbsent)合并各线程局部映射,键冲突由mergeFunction处理;必需参数为keyMapper、valueMapper和mergeFunction。
在并行流中直接使用
会抛出
,因为其底层依赖非线程安全的
。而
是专为并发收集设计的收集器,它内部使用
,天然支持多线程写入,无需额外同步。
为什么 toConcurrentMap 能保证线程安全
它不依赖单个共享 map 的并发控制(如加锁),而是让每个线程先构建自己的局部映射,再通过
的原子方法(如
、
)合并结果。键冲突时由你提供的
决定如何处理,避免竞态。
基本用法与必需参数
该收集器有三个必填参数:
keyMapper
:定义键的函数(如
)
valueMapper
:定义值的函数(如
)
mergeFunction
:键重复时的解决策略(如
保留旧值)
示例:
List people = Arrays.asList(...);ConcurrentMap idToName = people.parallelStream().collect(Collectors.toConcurrentMap(Person::getId,Person::getName,(oldVal, newVal) -> oldVal // 冲突时保留第一个 ));
可选参数:自定义 Map 工厂与并发级别
第四个参数是
,允许指定具体实现(如
或带初始容量/并发级别的构造);第五个参数是
,用于预估并发线程数,影响分段锁数量(默认为 16)。合理设置可减少争用:
若已知最多 8 个线程参与,可传
提升性能
工厂函数可传
常见陷阱与注意事项
虽然收集过程线程安全,但仍有几点必须注意:
输入流中的元素本身不应被多个线程同时修改(源数据需不可变或已同步)
必须是无副作用的纯函数;若抛异常,整个收集会失败
返回的是
,不是普通
,某些操作语义不同(如
是原子的)
不保证遍历顺序,也不提供强一致性迭代器
Collectors.toMapConcurrentModificationExceptionHashMapCollectors.toConcurrentMapConcurrentHashMapConcurrentHashMapmergeputIfAbsentmergeFunctionPerson::getIdPerson::getName(oldVal, newVal) -> oldValmapFactoryConcurrentHashMap::newconcurrencyLevel8() -> new ConcurrentHashMap<>(1024, 0.75f, 8)mergeFunctionConcurrentMapMapcomputeIfAbsent