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.AbstractList$Itr.checkForComodification(AbstractList.java:449) 处的 java.util.ConcurrentModificationException 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();
4

2 回答 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 Collection类是快速失败的,这意味着如果一个线程更改了一个集合,而另一个线程正在使用迭代器遍历它,则iterator.hasNext()oriterator.next()调用将抛出ConcurrentModificationException

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

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

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

解决方案 2:您可以在迭代时通过将代码包装在同步块中来锁定整个列表。如果应用程序高度并发,这种方法会对应用程序的可伸缩性产生不利影响。

解决方案 3:您可以使用ConcurrentHashMapandCopyOnWriteArrayList类,它提供了更好的可伸缩性,并且返回的迭代器ConcurrentHashMap.iterator()不会抛出ConcurrentModificationException,同时保持线程安全。

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

利用:

it.remove();

it它通过引用您的基础集合的 Iterator 删除当前对象list

避免:

list.remove(myObject);
于 2013-10-27T19:57:03.563 回答
1

看起来很奇怪,我的猜测是您List<Project> proj在迭代时在另一个线程中修改了列表()?

因为您不会以任何方式更改您提供给我们的代码中的列表。

您可以尝试使用列表saveProjects的副本调用该方法proj

于 2013-10-27T20:20:02.877 回答