Map java util concurrentmodificationexception

Java.util.ConcurrentModificationException Examples And Resolution

When you operate a java collection object use iterator, you may always meet java.util.ConcurrentModificationException error. It is because the java collection object has been changed while others still use the method iterator.next() to loop in it. Below is just an example code that can throw concurrent modification exceptions.

1. Java Concurrent Modification Exception Examples.

  1. When you execute the below java code, you may see ConcurrentModificationException like below.
Current phone is Apple Current phone is Google Current phone is Microsoft Exception in thread "main" java.util.ConcurrentHodificationException at java.uti1.ArrayList$Itr.checkForComodification(Unknown Source) at java.uti1.ArrayList$Itr.next(Unknown Source) at com.dev2qa.java.basic.collection.TestConcurrentModificationException.testListCMException(TestConcurrentModificationException.java:46) at com.dev2qa.java.basic.collection.TestConcurrentModificationException.main(TestC0ncurrentModificationException.java:19)
public static void testListCMException() < /* Initiate a ArrayList object. */ ListphoneList = new ArrayList(); phoneList.add("Apple"); phoneList.add("Google"); phoneList.add("Microsoft"); phoneList.add("Huawei"); phoneList.add("Xiao Mi"); phoneList.add("Vivo"); /* Get the object's iterator. */ Iterator it = phoneList.iterator(); /* Iterate the object. */ while(it.hasNext()) < String phone = it.next(); System.out.println("Current phone is " + phone); /* Remove the object.*/ if(phone.equalsIgnoreCase("microsoft")) < /* ArrayList changed after remove, so it.next() will throw ConcurrentModificationException. */ phoneList.remove(phone); >> >
public static void testMapCMException() < /* Initiate a Map object. */ MaposMap = new HashMap(); osMap.put("android", "android"); osMap.put("ios", "ios"); osMap.put("macos", "macos"); osMap.put("windows", "windows"); osMap.put("linux", "linux"); osMap.put("unix", "unix"); /* Get the map object's values collection. */ Collection vCollection = osMap.values(); /* Get vCollection' iterator. */ Iterator it = osMap.values().iterator(); /* Iterate vCollection. */ while(it.hasNext()) < String os = it.next(); System.out.println("OS is " + os); /* Add new object in the map.*/ if(os.equalsIgnoreCase("ios")) < /* After add, collection changed, so it.next() will throw ConcurrentModificationException. */ osMap.put("redhat", "redhat"); >> >
public void testSubListCMException() < ListfruitList = new ArrayList<>(); fruitList.add("Apple"); fruitList.add("Orange"); fruitList.add("Banana"); fruitList.add("Pear"); fruitList.add("hawthorn"); List subFruitList = fruitList.subList(0, 2); System.out.println(fruitList + " , " + subFruitList); fruitList.set(1, "Watermelon "); System.out.println(fruitList + " , " + subFruitList); // Add another fruit. fruitList.add("cherry"); /* Remove comment below code, get the sub list again after original list change can avoid ConcurrentModificationException. */ //subFruitList = fruitList.subList(0, 2); //Below code will throw ConcurrentModificationException, because original list fruitList changed. System.out.println(fruitList +" , "+subFruitList); >

2. How To Fix Java ConcurrentModificationException.

  1. Jdk1.5 or higher provides Concurrent Collection classes that you can use to avoid this exception. CopyOnWriteArrayList and ConcurrentHashMap are two example class.
  2. CopyOnWriteArrayList Example.
public static void testListWithoutCMException() < /* Initiate a CopyOnWriteArrayList object. */ ListlanguageList = new CopyOnWriteArrayList(); languageList.add("java"); languageList.add("c++"); languageList.add("python"); languageList.add("perl"); languageList.add("javascript"); languageList.add("go"); System.out.println("Strings before remove. "); /* Print each string in the list before remove.*/ for(String codingLanguage : languageList) < System.out.println(codingLanguage); >/* Get the object's iterator. */ Iterator it = languageList.iterator(); /* Iterate the object. */ while(it.hasNext()) < String codingLanguage = it.next(); /* Remove the object.*/ if(codingLanguage.equalsIgnoreCase("perl")) < languageList.remove(codingLanguage); languageList.add("scala"); >> System.out.println(""); System.out.println("Strings after remove. "); /* Print each string in the list after remove.*/ for(String codingLanguage : languageList) < System.out.println(codingLanguage); >>

Below is the output of the above source code.

List strings before remove java C++ python perl javascript go List strings after remove. java C++ python javascript go scala
public static void testMapWithoutCMException() < /* Initiate a ConcurrentHashMap object. */ MapdbMap = new ConcurrentHashMap(); dbMap.put("oracle", "oracle"); dbMap.put("mysql", "mysql"); dbMap.put("db2", "db2"); dbMap.put("sql server", "sql server"); dbMap.put("hadoop", "hadoop"); dbMap.put("mongodb", "mongodb"); /* Get the map object's values collection. */ Collection vCollection = dbMap.values(); /* Get vCollection' iterator. */ Iterator it = dbMap.values().iterator(); /* Iterate vCollection. */ while(it.hasNext()) < String db = it.next(); /* Add new object in the map.*/ if(db.equalsIgnoreCase("db2")) < dbMap.put("Big Table", "Big Table"); >> System.out.println("Map data after add. "); Set dbKeySet = dbMap.keySet(); Iterator dbKeySetIt = dbKeySet.iterator(); while(dbKeySetIt.hasNext()) < String db = dbKeySetIt.next(); System.out.println("Database is " + db); >>
Map data after add. Database is oracle Database is Big Table Database is db2 Database is mysql Database is hadoop Database is mongodb Database is sql server
public void testSubListCMException() < ListfruitList = new ArrayList<>(); fruitList.add("Apple"); fruitList.add("Orange"); fruitList.add("Banana"); fruitList.add("Pear"); fruitList.add("hawthorn"); List subFruitList = fruitList.subList(0, 2); System.out.println(fruitList + " , " + subFruitList); fruitList.set(1, "Watermelon "); System.out.println(fruitList + " , " + subFruitList); // Add another fruit in the list. fruitList.add("cherry"); /* get the sub list again after original list change can avoid ConcurrentModificationException. */ subFruitList = fruitList.subList(0, 2); //Below code will throw ConcurrentModificationException, because original list fruitList changed. System.out.println(fruitList +" , "+subFruitList); >
public void testListWithoutCMExceptionUseForLoop() < /* Initiate a Arraylist object. */ ListballList = new ArrayList(); ballList.add("football"); ballList.add("basketball"); ballList.add("volleyball"); System.out.println("List strings before remove. "); /* Print each string in the list before remove.*/ for(String ball : ballList) < System.out.println(ball); >int size = ballList.size(); for(int i = 0;i if("basketball".equalsIgnoreCase(ball)) < ballList.remove(ball); // After remove, should recalculate the size and i--. i--; size = ballList.size(); >> System.out.println(""); System.out.println("Strings after remove. "); /* Print each string in the list after remove.*/ for(String ball : ballList) < System.out.println(ball); >>

Источник

Читайте также:  Html response content type xml

Избавляемся от ConcurrentModificationException

Как известно, ConcurrentModificationException к многопоточности никакого отношения не имеет. Возникает эта гадость, когда мы пытаемся модифицировать коллекцию во время итерирования по ней. Как обычно, это имеет исторические корни: коллекции и итераторы появились в Java 1.2, в те времена избежать явного использования итератора при обходе коллекции было никак нельзя, так что предложение менять коллекцию посредством методов итератора не выглядело совсем ужасным:

Iterator iterator = collection.iterator(); while (iterator.hasNext()) < Object element = iterator.next(); if (iDontLikeThisElement(element)) < iterator.remove(); >> 

Не, всё же выглядело. Но никаких других вариантов не было. Позже в пятой джаве появляется цикл foreach, и использование итераторов становится преимущественно неявным:

for (E element : collection) < if (iDonLikeThisElement(element)) < collection.remove(element); // облом! ConcurrentModificationException! >> 

«Ишь чего захотели! Юзайте явные итераторы, дорогие кастомеры, и не выделывайтесь» — наверное что-то такое думали разработчики джава платформы работая над пятеркой.

В шестой джаве появляется пакет конкаренси. Теперь можно cделать так:

Set set = Collections.newSetFromMap(new ConcurrentHashMap<>()); 

И получить set который не кидается ConcurrentModificationException-ами. Но опять же счастье не совсем полное:

  1. Oбычно многопоточность нам вовсе не нужна
  2. Не подерживаются null ни в качестве элементов, ни ключей, ни значений. Да и ладно, честно сказать.
  3. Порядок элементов не определён и может меняться — вот это гораздо хуже. Т.е. если мы бежим по элементам и ведём некий подсчёт с потерей точности, то нас могут поджидать неприятные сюрпризы и разные результаты на одних и тех же наборах данных, что, скажем, не всегда хорошо. Так же бывают задачи, где желательно сохранить именно изначальный порядок данных. Ну и вот такие штуки тоже имеют место быть:
set.add("aaa"); set.add("bbb"); for (String s : set)
set.add("aaa"); set.add("bbb"); for (String s : set)
  1. В рамках одного треда можно добавлять и удалять элементы в любой момент без всяких эксепшенов. И конечно же за константное время.
  2. Можно хранить null-ы, если вдруг хочется.
  3. Элементы обходятся в том порядке в котором были добавлены.
  1. Удаляя элемент мы не будем обнулять ссылку на следующий, т. е. eсли итератор стоит на данном элементе, то он сможет пройти дальше.
  2. В конце списка поместим фэйковый элемент, который превращается в настоящий когда в список что-нибудь добавляют. Т.е. даже добравшись до конца списка итератор не упирается в null и может продолжить работу если в коллекции появляется новый элемент. Далее в коде этот фейковый элемент называется placeholder.
Читайте также:  Отличие break от continue java

  1. В начале у нас есть элементы A, B, C, D.
  2. Затем элементы C и D удаляются.
  3. Добавляется новый элемент E.

Ну и для константного времени доступа нам, очевидно, нужен хэшмап:

import java.util.AbstractSet; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; public class LinkedSet extends AbstractSet  < private static class LinkedElement < E value; boolean exists; LinkedElementprev; LinkedElement next; > private Map map = new HashMap<>(); private LinkedElement placeholder = new LinkedElement<>(); private LinkedElement head = placeholder; @Override public boolean isEmpty() < return head == placeholder; >@Override public int size() < return map.size(); >@Override public boolean contains(Object o) < return map.containsKey(o); >// здесь будут методы для добавления, удаления, итерирования > 
 @Override public boolean add(E e) < LinkedElementelement = map.putIfAbsent(e, placeholder); if (element != null) < return false; >element = placeholder; element.exists = true; element.value = e; placeholder = new LinkedElement<>(); placeholder.prev = element; element.next = placeholder; return true; > 
 @Override public boolean remove(Object o) < LinkedElementremovedElement = map.remove(o); if (removedElement == null) < return false; >removeElementFromLinkedList(removedElement); return true; > private void removeElementFromLinkedList(LinkedElement element) < element.exists = false; element.value = null; element.next.prev = element.prev; if (element.prev != null) < element.prev.next = element.next; element.prev = null; >else < head = element.next; >> 
 @Override public Iterator iterator() < return new ElementIterator(); >private class ElementIterator implements Iterator  < LinkedElementnext = head; LinkedElement current = null; LinkedElement findNext() < LinkedElementn = next; while (!n.exists && n.next != null) < next = n = n.next; >return n; > @Override public boolean hasNext() < return findNext().exists; >@Override public E next() < LinkedElementn = findNext(); if (!n.exists) < throw new NoSuchElementException(); >current = n; next = n.next; return n.value; > @Override public void remove() < if (current == null) < throw new IllegalStateException(); >if (map.remove(current.value, current)) < removeElementFromLinkedList(current); >else < throw new NoSuchElementException(); >> > 
Set set = new LinkedSet<>(); // . put some numbers set.stream().filter(v -> v % 2 == 0).forEach(set::remove); 

Понятно, что аналогично можно сконструировать и LinkedMap. Вот в общем-то и всё, ещё один велосипед готов. Почему подобным образом не доработали библиотечные LinkedHashMap и LinkedHashSet? Кто знает, возможно чтобы джависты завидовали джаваскриптистам.

Источник

Java – How ConcurrentModificationException can be handled ?

1. ConcurrentModificationException is thrown while iterating & removing:

CMEThrownWhileIteratingAndRemovingMap.java

package in.bench.resources.cme.examples; import java.util.HashMap; import java.util.Map.Entry; import java.util.Set; public class CMEThrownWhileIteratingAndRemovingMap < public static void main(String[] args) < // create HashMap HashMapmap = new HashMap(); // put few items map.put(1, "Google"); map.put(2, "Microsoft"); map.put(3, "Oracle"); map.put(4, "Apple"); map.put(5, "Facebook"); // getting entrySet() into Set Set entrySet = map.entrySet(); // iterate and remove items simultaneously for(Entry entry : entrySet) < int key = entry.getKey(); if(key == 4) < // try to remove, while iterating map.remove(key); >else < System.out.println(entry.getKey() + "\t" + entry.getValue()); >> > >
1 Google 2 Microsoft 3 Oracle Exception in thread "main" java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429) at java.util.HashMap$EntryIterator.next(HashMap.java:1463) at java.util.HashMap$EntryIterator.next(HashMap.java:1461) at in.bench.resources.cme.examples.CMEThrownWhileIteratingAndRemovingMap .main(CMEThrownWhileIteratingAndRemovingMap.java:25)

2. Fixing ConcurrentModificationException by using Iterator for iterating and removing an entry:

FixCMEUsingIterator.java

package in.bench.resources.cme.examples; import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; import java.util.Set; public class FixCMEUsingIterator < public static void main(String[] args) < // create HashMap HashMapmap = new HashMap(); // put few items map.put(1, "Google"); map.put(2, "Microsoft"); map.put(3, "Oracle"); map.put(4, "Apple"); map.put(5, "Facebook"); // getting entrySet() into Set Set entrySet = map.entrySet(); // Collection Iterator Iterator itr = entrySet.iterator(); // iterate and remove items simultaneously while(itr.hasNext()) < Entryentry = itr.next(); int key = entry.getKey(); if(key == 4) < // try to remove, while iterating itr.remove(); System.out.println("4th item safely removed using Iterator"); >else < System.out.println(entry.getKey() + "\t" + entry.getValue()); >> > >
1 Google 2 Microsoft 3 Oracle 4th item safely removed using Iterator 5 Facebook

3. Fixing ConcurrentModificationException by using ConcurrentHashMap:

Hope, you found this article very helpful. If you have any suggestion or want to contribute any other way or tricky situation you faced during Interview hours, then share with us. We will include that code here

  • Java – How to get all keys of a HashMap ?
  • Java – How to get all values of a HashMap ?
  • Java – How to get all Entries or Key-Value pairs of HashMap ?
  • Java – How to get size or length of HashMap ?
  • Java – How to check whether a particular key is present in HashMap ?
  • Java – How to check whether a particular value is present in HashMap ?
  • Java – How to check whether HashMap is empty or not ?.
  • Java – Adding one HashMap to another HashMap using putAll method
  • Java – How to delete an entry of HashMap ?
  • Java – How to delete all entries of HashMap ?
  • Java – Various ways to iterate through HashMap
  • Java – To reverse order the LinkedHashMap contents
  • Java – How ConcurrentModificationException can be handled
  • Java 8 – How to remove an entry from HashMap by comparing values
  • Java 8 – How to remove an entry from HashMap by comparing keys

Happy Coding !!
Happy Learning !!

Источник

Class ConcurrentModificationException

This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.

For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.

Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.

Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.

Источник

Оцените статью