部署WAR包至服务器运行测试用例时出现ConcurrentModificationException异常(本地运行正常)
解决服务器端
java.util.ConcurrentModificationException异常(本地无报错) 从你贴的异常栈来看,核心问题是java.util.ConcurrentModificationException——这个异常我碰到过好多次,通常要么是单线程里遍历集合的同时修改它,要么是多线程环境下一个线程在遍历,另一个线程偷偷改了集合。而本地跑正常、服务器报错,大概率是服务器的并发场景和本地不一样,比如请求并发量更高,或者线程池配置差异,把本地没暴露的问题给揪出来了。
一、先找到触发异常的业务代码
目前的栈信息只到Spring的框架层,没显示你的业务代码调用链,你得先把日志调详细:
- 把项目的日志级别改成
DEBUG,这样能打印出完整的调用栈,精准定位到是哪个Service/Controller里的集合操作出了问题。 - 看栈里有Grails相关的过滤器,你这是Grails项目对吧?可以结合Grails的请求追踪功能,快速定位到对应的处理方法。
二、常见问题场景及修复方案
1. 单线程遍历+修改集合的坑
比如你可能写过这种代码:
def dataList = someService.getData() for (item in dataList) { if (item.isExpired()) { dataList.remove(item) // 这里一运行就会炸! } }
怎么修?
- 用迭代器的
remove()方法,这是最标准的做法:
def iterator = dataList.iterator() while (iterator.hasNext()) { def item = iterator.next() if (item.isExpired()) { iterator.remove() // 用迭代器自己的remove方法就不会触发异常 } }
- 或者先拷贝一个集合副本再遍历修改原集合:
// 遍历副本,修改原集合 for (item in new ArrayList<>(dataList)) { if (item.isExpired()) { dataList.remove(item) } }
2. 多线程共享集合的线程安全问题
服务器端多请求并发的时候,如果你的代码里有全局静态集合,或者Spring Bean里的非线程安全集合(比如ArrayList、HashMap)被多个线程同时读写,本地单请求测试不会有问题,服务器高并发下必炸。
怎么修?
- 直接换成线程安全的集合实现:比如用
CopyOnWriteArrayList替代ArrayList,ConcurrentHashMap替代HashMap。 - 对集合的读写操作加锁:用
synchronized块或者ReentrantLock把集合的修改和遍历代码包裹起来,确保同一时间只有一个线程操作集合。 - 尽量避免全局共享可变集合:能把集合做成方法局部变量就别做成成员变量,每个请求单独创建集合实例最安全。
三、结合WebSphere服务器的特殊点排查
从栈里的com.ibm.ws.webcontainer能看出来你用的是WebSphere服务器,还要注意这两点:
- WebSphere的线程池默认配置比本地Tomcat(假设你本地用的是Tomcat)要大,并发请求更多,更容易触发线程安全问题。
- 检查WebSphere的类加载优先级,有没有可能集合类的加载版本和本地不一致?不过这个概率很低,优先排查代码的线程安全问题。
内容的提问来源于stack exchange,提问作者srinivasulu reddy
相关产品推荐
相关产品推荐

