You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring WebFlux请求构建器出现ConcurrentModificationException异常求助及推测验证

Spring WebFlux请求构建器出现ConcurrentModificationException异常求助及推测验证

大家好,我最近在Spring WebFlux项目里碰到了一个随机触发的ConcurrentModificationException,折腾了好一阵才定位到相关线索,现在把情况整理出来,想请各位帮忙看看我的推测是否准确。

首先贴一下异常的完整栈追踪:

java.util.ConcurrentModificationException
	at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1221)
	at org.springframework.web.reactive.function.client.DefaultClientRequestBuilder$BodyInserterRequest.<init>(DefaultClientRequestBuilder.java:210)
	at org.springframework.web.reactive.function.client.DefaultClientRequestBuilder.build(DefaultClientRequestBuilder.java:173)
	at org.springframework.web.reactive.function.client.DefaultWebClient$DefaultRequestBodyUriSpec.lambda$exchange$11(DefaultWebClient.java:453)
	at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:47)
	at reactor.core.publisher.Mono.subscribe(Mono.java:4496)
	at reactor.core.publisher.MonoSubscribeOn$SubscribeOnSubscriber.run(MonoSubscribeOn.java:126)
	at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84)
	at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:840)
Suppressed: java.lang.Exception: #block terminated with an error
	at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:103)
	at reactor.core.publisher.Mono.block(Mono.java:1712)

查看日志和Spring源码后,我发现异常触发的核心代码在DefaultClientRequestBuilder$BodyInserterRequest的构造方法里,具体是这一行:

Object id = attributes.computeIfAbsent(LOG_ID_ATTRIBUTE, name -> ObjectUtils.getIdentityHexString(this));

我自己琢磨了下,觉得问题可能出在这里:当前使用的attributes是一个非线程安全的HashMap,而且代码里直接使用attributes而非this.attributes,会不会导致意外引用了其他共享的Map实例?毕竟WebFlux是基于多线程调度的响应式框架,多个线程同时操作非并发安全的HashMap,很容易触发ConcurrentModificationException

如果把这行代码改成:

Object id = this.attributes.computeIfAbsent(LOG_ID_ATTRIBUTE, name -> ObjectUtils.getIdentityHexString(this));

是不是就能确保操作的是当前实例的成员变量,避免多线程下的并发修改冲突?

另外我也考虑过,是不是应该直接把这个Map替换成ConcurrentHashMap来从根本上保证线程安全,但先想确认我的这个引用问题的推测是否正确。有没有朋友遇到过类似的问题?或者能帮忙验证下这个思路对不对?

火山引擎 最新活动