You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Webflux场景下向HashMap插入数据出现竞态条件问题咨询

适配Spring Webflux场景的无锁解决方案

核心思路

响应式编程规范中禁止在异步回调中修改共享可变状态,你遇到的竞态问题本质是多个异步返回结果同时修改同一个HashMap导致的,不需要加锁也不需要额外的并发集合操作,直接用Reactor内置的聚合操作符即可从根源规避问题。

最优方案:使用Flux聚合操作符直接生成结果Map

你不需要自己提前声明Map来逐个填充,将20个Webflux调用返回的Mono合并为Flux后,直接用collectMultimap或自定义收集器生成目标结构即可,整个聚合过程由Reactor保证线程安全,无锁无阻塞,完全符合Webflux的设计规范。
示例代码如下:

// 1. 先构造所有文档上传请求的Mono列表
List<Mono<FileUploadLodgeReturnDetailsDTO>> uploadTasks = documentList.stream()
        .map(this::uploadSingleDocument) // 你的单个文档上传Webflux调用方法
        .toList();

// 2. 合并所有请求结果,直接聚合为目标Map结构
Mono<Map<DocumentType, List<FileUploadDetailsDTO>>> resultMap = Flux.merge(uploadTasks)
        .collect(
                // 初始容器
                () -> new HashMap<DocumentType, List<FileUploadDetailsDTO>>(),
                // 元素入库逻辑,单个聚合操作在Reactor中是线程安全的
                (map, dto) -> map.computeIfAbsent(
                        DocumentType.make(dto.getDocumentType()),
                        k -> new ArrayList<>()
                ).add(dto)
        );

后续你需要使用这个Map时,直接把resultMap拼接在你的响应式调用链中即可,不需要手动维护任何共享可变变量。

原有方案问题说明

  • 你之前用ConcurrentHashMap出现元素丢失,是因为containsKey、get、put是三个独立的操作,不具备原子性,就算用ConcurrentHashMap也无法避免竞态。如果非要在回调中修改Map,应该用ConcurrentHashMap.computeIfAbsent这个原子操作来插入元素,不会出现丢数据的问题,但依然属于共享可变状态的写法,不推荐在Webflux中使用。
  • 加synchronized会阻塞Webflux的事件循环线程,直接丧失响应式架构的非阻塞性能优势,完全不可取。

内容的提问来源于stack exchange,提问作者Amol Kshirsagar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 21:15:03