Spring Boot中CompletableFuture allOf合并结果出现重复与缺失问题
问题分析与解决方案
结论
合并结果环节不会导致重复或缺失,问题根源在@Async方法中的共享可变对象。
具体问题点
你的@Async方法中使用的unitaConversioneInXml如果是类的成员变量(而非方法局部变量),会被多个异步线程共享并发修改:
- 当线程A正在生成某条
rigaQ对应的XML时,线程B可能已经修改了unitaConversioneInXml的RecordTypeQ值,导致线程A最终生成的XML使用了线程B的参数,出现重复。 - 并发修改还可能导致部分
rigaQ的参数被覆盖,对应的XML直接缺失。
另外,你在方法内使用Collections.synchronizedList是多余的——因为每个异步任务的循环是单线程串行执行的,普通ArrayList完全足够,同步列表反而会带来不必要的性能开销。
修复代码
将unitaConversioneInXml改为方法局部变量,让每个异步任务拥有独立的实例:
@Async public CompletableFuture<List<byte[]>> genereteXmlsWithMultithreading(RigheCorrelate righeCorrelate) { // 每个任务创建独立的转换实例,避免线程间状态污染 UnitaConversioneInXml unitaConversioneInXml = new UnitaConversioneInXml(); unitaConversioneInXml.setRecordTypeANABI((RecordTypeANABI) serialize(righeCorrelate.getRigaANABI())); unitaConversioneInXml.setRecordTypeT07((RecordTypeTypeT) serialize(righeCorrelate.getRigaT())); List<byte[]> xmlFilesPerTask = new ArrayList<>(); for (String rigaQ : righeCorrelate.getRigheQ()) { unitaConversioneInXml.setRecordTypeQ((RecordTypeTypeQ) serialize(rigaQ)); try { xmlFilesPerTask.add(XmlUtils.generateXml(unitaConversioneInXml.mapToXmlClass(), jaxbContext)); } catch (JAXBException e) { throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Errore nella generazione di un file xml", e); } } log.info("Elaborati {} xmls", xmlFilesPerTask.size()); return CompletableFuture.completedFuture(xmlFilesPerTask); }
额外检查项
- 确认
jaxbContext是线程安全的:JAXBContext本身是线程安全的,可放心共享。 - 确认
serialize方法无共享状态:如果该方法依赖类成员变量或其他共享资源,需确保其线程安全。
内容的提问来源于stack exchange,提问作者Saverio Mirko Viola
相关产品推荐
相关产品推荐

