我有以下代码
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) 在java.util.AbstractList $ Itr.next(AbstractList.java:420)
如何使用next或with iterator解决此问题?
编辑1
我正在调用saveProjects的代码片段
projectList.add(proj);
for (Project persist: projectList) {
persist.setProjectId("K7890");
persist.setName(fileName);
myDAO.saveProjects(projectList);
}
projectList.clear();
答案 0 :(得分: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()
或iterator.next()
调用将抛出{ {1}}。
即使是同步的集合包装类ConcurrentModificationException
和SynchronizedMap
也只是有条件地线程安全的,这意味着所有单独的操作都是线程安全的,但复合操作的控制流程取决于先前操作的结果可能会受到线程问题的影响。 (SynchronizedList
!这可能不起作用)
多线程访问情况的解决方案
解决方案1 :您可以将列表转换为List myList = Collections.synchronizedList (myList)
的数组并迭代数组。如果列表很大,则不建议使用此方法。
解决方案2 :您可以在迭代时锁定整个列表,方法是将代码包装在同步块中。如果应用程序高度并发,则此方法会对应用程序的可伸缩性产生负面影响。
解决方案3 :您可以使用list.toArray()
和ConcurrentHashMap
类,
它提供了更好的可伸缩性,CopyOnWriteArrayList
返回的迭代器不会抛出ConcurrentHashMap.iterator()
,同时保留线程安全性。
单线程访问情况的解决方案
使用:
ConcurrentModificationException
它通过Iterator it.remove();
删除当前对象,该Iterator具有对基础集合it
的引用。
避免:
list
答案 1 :(得分:1)
看起来很奇怪,我的猜测是你在迭代它时修改另一个线程中的列表(List<Project> proj
)?
因为您没有以任何方式更改您提供给我们的代码中的列表。
您可以尝试使用saveProjects
列表的副本调用proj
方法。