多线程修改了ArrayList , 如何知道被谁修改的?
public void method(){
...
for(Object obj: finalObjects){
....
doSth(obj);
....
}
}
我在主线程遍历 ArrayList 的时候,发生了 java.util.ConcurrentModificationException
已检查 doSth
并没有修改 全局变量 finalObjects
,所以我怀疑是某个异步方法在我遍历期间修改了这个变量,由于系统庞大,没法直接查找哪里修改了它,有没有办法在运行时获取,是哪个地方的异步,或者是哪个线程,修改了 finalObjects
导致异常发生?
请教各位大佬 ,谢谢 !!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
有完整的程序吗,我可以帮你分析
有完整的程序吗,可以帮你分析
世界是科学的,先看下finalObject是在哪里的,被使用的地方有哪些,另外哪里有额外的线程在跑,你需要知道,然后一个一个的排查. 你这点信息,塞牙缝都不够
最优解决方案:
用
Vector
替换ArrayList
“我偏不”的解决方案:
出现
java.util.ConcurrentModificationException
,是因为在
for(X : Xs)
的循环执行过程中,迭代器检测到元素数目有变化因此,换成
for(int i; i <; i++)
就可以避免这个异常了(当然,如果删除了元素就有空指针问题)“让一个方法独占cpu直到执行完”,这描述……
我理解应该是这么个意思吧:
似乎表面上是可以解决问题了
但是每发现个问题都得加个
synchronized
,所以,为啥不直接用Vector
呢你应该向如上的方式修改你的代码。而不是直接依赖某个对象的属性,最好的做法应该是提供 get 方法在方法的内部返回时拷贝一个新的
list
,这样可以保证属性的安全性,保证外部的修改不会影响到内部的属性。因你目前的实现依赖一个对象的属性,你无法保证它不会被其它地方修改,所以你应该要修改你的循环实现方式。
多庞大? 可以尝试 用ide的全局搜索 查查代码看看
针对这个问题 LZ 可以深入研究一下
ConcurrentModificationException
产生的原因:java 的增强 for 循环默认使用的 iterator 迭代器的 hasNext 和 next 来遍历元素。这样便不难理解这个问题的出现原因了。
你在其他地方执行了 remove 或者 add 方法,这个方法只会修改
modCount
值不会修改expectedModCount
的内容,所以在迭代器调用next
时候校验就会抛出异常所以问题找到了解决这个问题就简单了
方案一
如果是 remove 操作,找到你其他地方remove,修改成迭代器的方式
方案二
直接使用
CopyOnWriteArrayList
替换掉你的ArrayList
,前者在add 和 remove 时候都使用了 lock,很好的避免了这个问题。小编为订阅号「码匠笔记」号主,先后就职于 ThoughtWorks、阿里巴巴等互联网公司的经验分享,包含但不限于 JAVA、并发编程、性能优化、架构设计、小程序、开源软件等。有兴趣可以关注一波,一起学习、讨论。
很感谢各位的回答。只是解决这个问题,如@kevinz 那样,就可以了。
但是我的目的是想跟踪这个变量在这一段代码执行过程中,还有哪个线程修改了它。不过看来是很困难,我是一点头绪都没有。