列表 ConcurrentModificationException

3
我有以下的代码
public void saveProjects(List<Project> proj) throws DatabaseException {
    for (Project listItems: proj) { // error here

        insertProjects(listItems);
    }
}

private void insertProjects(Project prj) throws DatabaseException {
    commitObjects(prj);
}

当我执行以上代码时,for (Project listItems: proj) {处报以下异常:

java.util.ConcurrentModificationException at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:449) at java.util.AbstractList$Itr.next(AbstractList.java:420)

使用next或iterator如何解决这个问题?
编辑1
调用saveProjects的代码片段。
projectList.add(proj);
  for (Project persist: projectList) {
       persist.setProjectId("K7890");
       persist.setName(fileName);

          myDAO.saveProjects(projectList);

     }
  projectList.clear();

commitObjects(prj)是做什么的?它是否以某种方式修改了List<Project> proj - Hovercraft Full Of Eels
@MaximShoustin CallableStatement 是数据库连接类型。 - Jacob
你能发布调用saveProjects的代码吗? - Maxim Shoustin
很奇怪,看起来你没有修改列表。在迭代列表之前,可以尝试使用 Collections.unmodifiableList(...) 包装列表吗?你是否同时调用了一些东西? - Ortwin Angermeier
你的堆栈跟踪信息显示代码中哪些行可以更有用。 - Peter Lawrey
显示剩余6条评论
2个回答

6

从代码中

for (Project persist: projectList) { 
     persist.setProjectId("K7890");
     persist.setName(fileName);

      myDAO.saveProjects(projectList); 
 }

projectList.clear(); // <-- clear might cause to this Exception

参考

为什么在使用迭代器时会出现ConcurrentModificationException异常?

java.util集合类是快速失败的,这意味着如果一个线程在遍历集合时另一个线程修改了它,iterator.hasNext()iterator.next()调用将抛出ConcurrentModificationException异常。

即使是同步的集合包装类SynchronizedMapSynchronizedList也只是有条件地线程安全,这意味着所有单独的操作都是线程安全的,但是流程控制取决于前一次操作结果的复合操作可能会有线程问题。(List myList = Collections.synchronizedList(myList)!这里可能行不通)

多线程访问情况的解决方案

解决办法1:您可以使用list.toArray()将列表转换为数组,并在数组上进行迭代。如果列表很大,则不建议使用此方法。

解决办法2:您可以在迭代时锁定整个列表,方法是将您的代码包装在同步块内部。如果应用程序高度并发,这种方法会对可扩展性产生负面影响。

解决办法3:您可以使用ConcurrentHashMapCopyOnWriteArrayList类,这些类提供更好的可扩展性,并且ConcurrentHashMap.iterator()返回的迭代器不会抛出ConcurrentModificationException异常,同时保留线程安全性。

单线程访问情况的解决方案

使用:

it.remove();

通过具有对底层集合list的引用的迭代器it,它会移除当前对象。

避免:

list.remove(myObject);

Maxim,如果我从第二个循环中删除for循环,则它将停止保存记录。 - Jacob
如果你提交了 insertProjects(listItems); 仍然出现这个错误? - Maxim Shoustin
你的意思是直接调用 insertProjects(listItems); 吗? - Jacob
切换注释,如 //insertProjects(listItems); 可能连接会有所作为。我对数据访问逻辑不太熟悉。 - Maxim Shoustin
抱歉,即使将 insertProjects(listItems); 注释掉,它仍会抛出异常。 - Jacob
显示剩余3条评论

1
看起来很奇怪,我猜测您在遍历列表 (List<Project> proj) 的同时在另一个线程中修改它?
因为您在给我们的代码中没有以任何方式更改列表。
您可以尝试使用 proj 列表的副本调用 saveProjects 方法。

这最多只是一个评论(就像你已经做过的那样),而不是一个答案。 - Jeroen Vannevel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接