Apart from the NullPointerException and ClassNotFoundException, ConcurrentModificationException is another nightmare for Java developers. What makes this error tricky is the word concurrent, which always mislead Java programmers that this exception is coming because multiple threads are trying to modify the collection at the same time. Then begins the hunting and debugging, they spent countless hours to find the code which has the probability of concurrent modification. While in reality, ConcurrentModficationException can also come in a single-threaded environment.
To give you an example, just loop over a list using for loop and try to remove one element, you will get the ConcurrentModificatoinExcetpion? Why? because you broke the rule of not modifying a Collection during iteration.
How does Java know to throw ConcurrentModificationExeption? It uses a transient variable called modCount, which keeps track of how many times a list is modified structurally. Structural modifications are those that change the size of the list, which may affect the progress of iteration and may yield incorrect results.
How does Java know to throw ConcurrentModificationExeption? It uses a transient variable called modCount, which keeps track of how many times a list is modified structurally. Structural modifications are those that change the size of the list, which may affect the progress of iteration and may yield incorrect results.
Both Iterator and ListIterator use this field to detect unexpected change. Other methods of List which structurally modify List also use this method like add(), remove().
Problem: loop over an ArrayList and remove selected elements, but remove() is throwing "Exception in thread "main" java.util.ConcurrentModificationException".
Cause: The real cause of ConcurrentModfiicationException is inconsistent modCount. When you are iterating over ArrayList then Iterator's next() method keep track of modCount. If you modify the collection by adding or removing elements then modCount will change and it will not match with the expected modCount, hence Iterator will throw ConcurrentModificationException.
Here is the code snippet from the hasNext() method which shows there is check for modCount:
Now if you check this checkForComodification() method, you will find what I just said:
Solution: Use Iterator if you are doing it on the single-threaded environment, otherwise use concurrent collection classes like CopyOnWriteArrayList to remove elements while you are looping over it.
If you uncomment the commented code in the first loop and second loop, you will get the following exception:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at dto.ReverseArrayInPlace.main(ReverseArrayInPlace.java:28)
because we are using ArrayList's remove() method. In the second example, we have used the remove() method of Iterator and that's why we are successfully able to delete selected elements from the ArrayList without ConcurrentModificationException.
That's all about how to deal with ConcurrentModificationException in Java. The biggest thing to learn and remember is that this error can come even if you have just one thread modifying collection like removing elements while looping over the list.
Problem: loop over an ArrayList and remove selected elements, but remove() is throwing "Exception in thread "main" java.util.ConcurrentModificationException".
Cause: The real cause of ConcurrentModfiicationException is inconsistent modCount. When you are iterating over ArrayList then Iterator's next() method keep track of modCount. If you modify the collection by adding or removing elements then modCount will change and it will not match with the expected modCount, hence Iterator will throw ConcurrentModificationException.
Here is the code snippet from the hasNext() method which shows there is check for modCount:
public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; }
Now if you check this checkForComodification() method, you will find what I just said:
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
Solution: Use Iterator if you are doing it on the single-threaded environment, otherwise use concurrent collection classes like CopyOnWriteArrayList to remove elements while you are looping over it.
Solving ConcurrentModificationException while Iterating over ArrayList in Java
Here is the Java program to demonstrate one scenario where you get the ConcurrentModificationException even if just one thread is modifying the ArrayList. In this example, we are looping over ArrayList using advanced for loop and removing selected elements, but because we are using ArrayList's remove() method.import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; /** * Java Program to demonstrate how to deal with * ConcurrentModificationException. * Unlike the name suggests, this error can come even if only * one thread is modifying the collection e.g. List. * It happens when you modify collection * while iterating over it e.g. adding new element or removing elements. * * If you want to remove elements while traversing list then * make sure you use Iterator's remove() method or not ArrayList's remove() * method() to avoid ConcurrentModificationExcetpion. * * @author WINDOWS 8 * */ public class ConcurrentModExceptionDemo{ public static void main(String args[]) { List<String> listOfPhones = new ArrayList<String>(Arrays.asList( "iPhone 6S", "iPhone 6", "iPhone 5", "Samsung Galaxy 4", "Lumia Nokia")); System.out.println("list of phones: " + listOfPhones); // Iterating and removing objects from list // This is wrong way, will throw ConcurrentModificationException for(String phone : listOfPhones){ if(phone.startsWith("iPhone")){ // listOfPhones.remove(phone); // will throw exception } } // The Right way, iterating elements using Iterator's remove() method for(Iterator<String> itr = listOfPhones.iterator(); itr.hasNext();){ String phone = itr.next(); if(phone.startsWith("iPhone")){ // listOfPhones.remove(phone); // wrong again itr.remove(); // right call } } System.out.println("list after removal: " + listOfPhones); } } Output : list of phones: [iPhone 6S, iPhone 6, iPhone 5, Samsung Galaxy 4, Lumia Nokia] list after removal: [Samsung Galaxy 4, Lumia Nokia]
If you uncomment the commented code in the first loop and second loop, you will get the following exception:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at dto.ReverseArrayInPlace.main(ReverseArrayInPlace.java:28)
because we are using ArrayList's remove() method. In the second example, we have used the remove() method of Iterator and that's why we are successfully able to delete selected elements from the ArrayList without ConcurrentModificationException.
How to Fix ConcurrentModficiationException in Java?
Here is a summary of important points about solving ConcurrentModificationException while looping or Iterating over ArrayList in Java :That's all about how to deal with ConcurrentModificationException in Java. The biggest thing to learn and remember is that this error can come even if you have just one thread modifying collection like removing elements while looping over the list.
So, while the name suggest concurrentModification it doesn't always mean that multiple threads are modifying the Collection or ArrayList at the same time. The simplest scenarios when this error comes when you are iterating over an ArrayList in Java and then using ArrayList.remove() method to remove objects.
Same is true when you sue the for each loop of Java 5 to loop over Collection or List as it internally uses Iterator. You can fix ConcurrentModificationException by changing your code and instead of using ArrayList.remove() method just use Iterator.remove() method in Java.
Related troubleshooting guides
Here are some handy Java tips to solve some common errors and exceptions in Java:
Related troubleshooting guides
Here are some handy Java tips to solve some common errors and exceptions in Java:
- How to deal with java.lang.NoClassDefFoundError: org/apache/xmlbeans/XmlObject? (solution)
- How to solve "could not create the Java virtual machine" error in Java? (solution)
- Fixing java.lang.unsupportedclassversionerror unsupported major.minor version 50.0 (solution)
- java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory error (solution)
- How to solve java.lang.ClassNotFoundException: com.mysql.jdbc.Driver error? (hint)
- How to solve java.lang.classnotfoundexception oracle.jdbc.driver.oracledriver? (solution)
- java.lang.ClassNotFoundException : org.Springframework.
Web.Context.ContextLoaderListener (solution) - How to fix 'javac' is not recognized as an internal or external command (solution)
- How to fix Caused By: java.lang.NoClassDefFoundError: org/apache/log4j/Logger (solution)
- How to solve java.lang.OutOfMemoryError: Java Heap Space in Eclipse, Tomcat? (solution)
Still i get concurrentModificationException
ReplyDelete// LocalDate today = LocalDate.now();
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
String today = sd.format((DateUtil.getCurrentDate()));
List orderDetail = new ArrayList();
orderDetail = this.orderDetailDao.getAllOrders(hotel.getId());
if (orderDetail != null){
System.out.println("orderDetail....."+orderDetail);
for(Iterator objOrderDetail = orderDetail.iterator();objOrderDetail.hasNext();){
OrderDetailDTO objDetail = objOrderDetail.next();
System.out.println("obj....."+objDetail);
if(today.equals(sd.format(objDetail.getCreatedDate()))){
System.out.println("dd=" + today);
List toppings = new ArrayList();
toppings = this.toppingDao.getToppingsByItemId(objDetail.getId());
String top = String.join(",", toppings);
System.out.println("top " + top);
objDetail.setToppingName(top);
orderDetail.add(objDetail);
System.out.println("obj.............."+objDetail);
//objOrderDetail.remove();
}
}
}
System.out.println("orderDetail List......"+orderDetail);
return orderDetail;
Please let me know if any drawback in using below code
ReplyDeleteList listOfPhones_Ashish = new ArrayList
(Arrays.asList( "iPhone 6S", "iPhone 6", "iPhone 5", "Samsung Galaxy 4", "Lumia Nokia"));
System.out.println("list of phones: " + listOfPhones_Ashish);
for(int i=0;i<listOfPhones_Ashish.size();i++){
if(listOfPhones_Ashish.get(i).startsWith("iPhone")){
listOfPhones_Ashish.remove(i);
--i;
}
}
System.out.println("After my removal process list is "+listOfPhones_Ashish);
no, works the same way as iterators. Only for-in construct results in this exception.
DeleteIf you are using Java 8 and above, just use list.filter to filter out and return a list with the items that satisfies a condition.
ReplyDeleteAlso, wrap the list in a syncronised object so only one callaer can access and modify it
I have never tried that approach but sounds promising, did you tried it on production yet?
Delete