I have the following code
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);
}
When I am executing the above, I am getting the following exception at 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)
How can I resolve this issue with usage of next or with iterator?
Edit 1
Code snippet where I am calling saveProjects
projectList.add(proj);
for (Project persist: projectList) {
persist.setProjectId("K7890");
persist.setName(fileName);
myDAO.saveProjects(projectList);
}
projectList.clear();
From code
for (Project persist: projectList) {
persist.setProjectId("K7890");
persist.setName(fileName);
myDAO.saveProjects(projectList);
}
projectList.clear(); // <-- clear might cause to this Exception
Reference
Why do you get a ConcurrentModificationException when using an iterator?
The java.util Collection
classes are fail-fast, which means that if one thread changes a collection while another thread is traversing it through with an iterator the iterator.hasNext()
or iterator.next()
call will throw ConcurrentModificationException
.
Even the synchronized collection wrapper classes SynchronizedMap
and SynchronizedList
are only conditionally thread-safe, which means all individual operations are thread-safe but compound operations where flow of control depends on the results of previous operations may be subject to threading issues. (List myList = Collections.synchronizedList (myList)
! It may not work here)
Solutions for multi-thread access situation
Solution 1: You can convert your list to an array with list.toArray()
and iterate on the array. This approach is not recommended if the list is large.
Solution 2: You can lock the entire list while iterating by wrapping your code within a synchronized block. This approach adversely affects scalability of your application if it is highly concurrent.
Solution 3: You can use the ConcurrentHashMap
and CopyOnWriteArrayList
classes,
which provide much better scalability and the iterator returned by ConcurrentHashMap.iterator()
will not throw ConcurrentModificationException
while preserving thread-safety.
Solution for single-thread access situation
Use:
it.remove();
It removes the current object via the Iterator it
which has a reference to your underlying collection list
.
Avoid:
list.remove(myObject);