Java 单独列表上的ConcurrentModificationException不清楚
在一个类中,我有两种方法:Java 单独列表上的ConcurrentModificationException不清楚,java,concurrency,Java,Concurrency,在一个类中,我有两种方法: public void notifyResult(List<Road> result) { ArrayList<RoadOverlay> tempRoads = new ArrayList<>(); for(Road road:result){ // Computes and stores the overlays // ... tempRoads.add(new RoadOverl
public void notifyResult(List<Road> result) {
ArrayList<RoadOverlay> tempRoads = new ArrayList<>();
for(Road road:result){
// Computes and stores the overlays
// ...
tempRoads.add(new RoadOverlay());
}
//switch field when update is done
this.positions = tempRoads;
}
}
private void drawRoadsVO(GL gl) {
// keep a reference on the current instance of the field
// to avoid concurrent modification in notifyResult
ArrayList<RoadOverlay> positionsCopy = this.positions;
int vertexCount = 0;
for (RoadOverlay road : positionsCopy) { //ConcurrentModificationException here
// ...
}
}
public void notifyResult(列表结果){
ArrayList tempRoads=新的ArrayList();
用于(道路:结果){
//计算并存储覆盖
// ...
tempRoads.add(新道路覆盖层());
}
//更新完成时切换字段
这个位置=临时道路;
}
}
私人作废提款单(德国劳埃德船级社){
//在字段的当前实例上保留引用
//避免notifyResult中的并发修改
ArrayList PositionScope=this.positions;
int vertexCount=0;
对于(道路覆盖层道路:位置透视){//ConcurrentModificationException此处
// ...
}
}
这两个方法都在不同的线程中运行。在渲染内部,我没有对列表进行任何更改,据我所知,我在单独的列表上工作,那么这如何产生CME呢?
我正在努力解决这个问题,任何线索都欢迎。我尽量避免使用同步的惩罚
问候
在代码中编辑注释通常最好制作列表的完整副本
ArrayList<RoadOverlay> positionsCopy = new ArrayList<Integer>(this.positions);
只有当列表的elementData
在结构上被修改时,才能抛出ConcurrentModificationException
结构修改是指改变列表大小的修改,
或者以某种方式干扰它,使迭代进行中
可能会产生错误的结果
问题是在drawRoadsVO方法中,您的var PositionScope实际上不是一个副本,而是对同一对象this.positions的引用 为了制作真实的副本,你应该
ArrayList<RoadOverlay> positionsCopy = new ArrayList(this.positions);
ArrayList positions=新的ArrayList(this.positions);
//复制以避免并发修改
您不复制列表。您只是有两个不同的引用指向同一个实例。我知道这不是一个浅拷贝,但它必须确保在同一个实例上保持遍历。你认为那没用?问题是,正如你所说,你的方法运行在不同的线程上。当您在同一实例上操作时,当您在drawRoadsVO
中读取列表时,一个线程可能会修改该列表(这就是抛出CME的原因)。因此,在读取之前,您需要创建一个深度副本,或者使用线程安全的数据结构。好的,但是在第一种方法中,我在每次调用时创建一个新实例,所以我仍然需要同步?是的,我知道我应该更喜欢同步的深度副本,但此代码使用大量对象呈现OpenstreetMap中的道路层,我正在寻找每一个表演的热门。没有其他线程或方法修改集合。我将尝试将其设置为volatile,以防jvm在curtainHmm后面做奇怪的事情,现在我无法想象volatile
如何解决这个问题。在ArrayList.Itr
类CME的何处抛出?你能发布堆栈头跟踪吗?你是对的,它不会改变任何东西。这里有一个堆栈跟踪:java.util.ConcurrentModificationException位于java.util.ArrayList$Itr.checkForComodification(未知源代码)位于java.util.ArrayList$Itr.next(未知源代码)位于org.mycompany.RoadProvider.drawRoadsVO[…],仍然需要Volatile来保证可见性checkForComodification()
包含if(modCount!=expectedModCount)抛出新的ConcurrentModificationException()代码>所以结构修改发生在某个地方。对于调试,您可以在For循环之前创建positionsCopy
的深度副本,然后使用try{}catch(ConcurrentModificationException ex){//创建另一个positionsCopy`的深度副本,并与第一个深度副本进行比较,或者使用java调试器在此处创建断点}`好的,我已经找到了问题所在。由于您提供了有关modcount的详细信息,我注意到modcount在渲染过程中发生了变化。这是notifiedResult中闭包的一个蹩脚位置,它在每次循环迭代中都会导致从局部到字段的切换。是的,很差劲。无论如何,谢谢你的帮助!当做
ArrayList<RoadOverlay> positionsCopy = new ArrayList(this.positions);