Can changing members of values of HashMap cause java.util.ConcurrentModificationException - java

The below code is throwing concurrent Modification exception , the line where the exception is pointing is the first line of for loop
private synchronized void updateAllCacheValues() {
for (Map.Entry<Configurations, SalesConfiguration> entry : ConfigurationCache.entrySet()) {
Configurations conf = entry.getKey();
SalesConfiguration saleConfiguration = ConfigurationCache.get(conf);
Map<String, String> newMap = generateKeyValueMapFromConfigurations(conf);
lastLoadTimestamp = new Date();
saleConfiguration.setMap(newMap, lastLoadTimestamp);
}
logger.debug("Successfully updated all cached configurations., cache size " + ConfigurationCache.size() + "LAST_LOAD_TIME" + lastLoadTimestamp);
}
Below is the exception trace
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 com.learning.java.daily.updateAllCacheValues(ConfigurationLoader.java:237)
at com.learning.java.daily.updateAllCacheValues.impl.ConfigurationLoader.loadConfigurations(ConfigurationLoader.java:156)
I am not able to guess what could have caused this exception , because I wrote a sample test where I am modifying the attributes of the value of Map but concurrent modification exception did not appear.

To answer the question in your title: No, modifying value objects in your HashMap while iterating the entry set cannot alone produce a ConcurrentModificationException. There must be something else going on.
Could either the call to generateKeyValueMapFromConfigurations() or to saleConfiguration.setMap() modify the map? Might it be that your ConfigurationCache could be modified by some other, concurrent thread?? I know I am just guessing, it’s the best we can do with the information at hand.

I think this line is the culprit.
saleConfiguration.setMap(newMap, lastLoadTimestamp);
Literally ConcurrentModificationException comes when you update a map entry while iterating through it. Could you please comment out that line and check whether you are getting the exception anymore? If not you need to change the logic so that you do not change the map entries while iterating through them.

You are iterating entryset. So, modifying the entryset values is not allowed while you are iterating it. Use ConcurrentHashMap instead of HashMap.
Here is the analysis.
We can modify the key/value's attributes. But we cannot modify the map by adding or deleting elements to the map while we iterate. Suppose a map has five elements, while we iterate it, we can neither add an element to map nor delete an element from map. For this, we should use ConcurrentHashMap.
Hope it is more clear now.

Related

LinkedHashMap -> java.util.ConcurrentModificationException

I am getting ConcurrentModificationException when executing the following code:
public void refreshAvailableCaseSettings() throws Exception {
//getAvailableCases() returns reference to the instance variable
LinkedHashMap<Integer, CaseSetting> cases = getAvailableCases();
/* java.util.ConcurrentModificationException even after trying entryset()
for(Map.Entry<Integer, CaseSetting> entry : cases.entrySet()){
entry.getValue().refresh(false);
}
*/
// java.util.ConcurrentModificationException
Iterator casesIterator = cases.values().iterator();
while (casesIterator.hasNext()) {
CaseSetting caseSetting = casesIterator.next();
//refresh() updates caseSetting state by getting setting info from DB
caseSetting.refresh(false);
}
}
Error:
java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextNode(LinkedHashMap.java:719)
at java.util.LinkedHashMap$LinkedEntryIterator.next(LinkedHashMap.java:752)
at java.util.LinkedHashMap$LinkedEntryIterator.next(LinkedHashMap.java:750)
I am not modifying the map by adding or removing elements. Please help me to understand the issue here.
The general contract for using iterators is this:
While an iterator over a collection is in progress, the underlying collection must not be modified.
You can do whatever you want on the elements of the collection, but you must not touch the collection itself.
You are getting a ConcurrentModificationException because a part of your code within the while loop does exactly that - it changes the underlying collection.
A standard approach is to either (a) create a new copy of the collection and iterate over this read-only copy, or (b) put the changes into a separate collection.
What refresh function does ? According to my understanding you are getting these only because you are modifided HashMap while iterating it,
I used to get these error when I used to put something in map, means size was increasing.
Also you need to put everything in question, like CaseSetting class

How to solve java.util.NoSuchElementException: for HashMaps and ArrayLists?

Hi so I keep on having the java.util.NoSuchElementException for my code in two instances
In the first instance:
it says
1)
Java.util.NoSuchElementException null in java.util.ArrayList$ltr
line. I'm confused do I need an iterator for both the Hashmap values and for the Arraylist MaxCoPurchase as well? I'm just very confused.
2) The second instant when the
Java.util.NoSuchElementException comes up with the following line:
null in (Java.util.HashMap$HashIterator)
I'm confused once again.
If anyone could help me and have some suggestions or even code fixes that would be great
In the first case, the maxCoPurchase collection is clearly empty, probably the map as well.
In the second case, the maxMap is clearly empty. This is poor code which you should rewrite. When you save the maximum value you should also somehow save its key directly, instead of having to search for it. Or at least break out of the loop when you've found it.
In both cases, instead of iterating the key set and calling get() to get the associated value, you should iterate the entry set, which gives you the key and the value at the same time.
This exception is thrown when the collection is empty (in your case) or it does not contain the next value(especially when you are iterating it).
First case: A proper null check for the Arraylist "maxCoPurchase" will avoid this exception.
Second case: A proper null check for the HashMap "maxMap" will avoid this exception.
I hope this helps.

Getting java.util.ConcurrentModificationException

I executed the following code
Map<String, SyncPrimitive> syncPrimitives = new HashMap<String, SyncPrimitive>();
for (SyncPrimitive primitive : this.getSyncPrimitives()) {
String groupId = primitive.getId();
primitive.onConnect(groupId);
}
Then I' getting the following exception
Error while calling watcher
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
at java.util.HashMap$KeyIterator.next(HashMap.java:828)
In the onConnect method the primitive oject is modified. How can I overcome this issue?
You could not modify collection during iteration it with for-each. If you want to modify it, use Iterator.
This kind of exceptions pretty clear described in documentation:
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.
See related questions:
How to modify a Collection while iterating using for-each loop without ConcurrentModificationException?
Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop
Java: adding elements to a collection during iteration

How to remove and add elements to TreeMap while iterating?

I want to write code like this -
for (Map.Entry<Long, Integer> e : map.entrySet()){
map.remove(k);
map.put(x, value);
}
but I got java.util.ConcurrentModificationException
I tried to use Iterator also but I got the same Exception
Explanation why it caused ConcurrentModificationException
map.remove(k);
map.put(x, value);
for-each loop also internally create a iterator of the entrySet of map. While iterating over map you have modified the structure of the map by putting the value again to the map (map.put(x,value)) which cause this ConcurrentModificationException.
It is even well explained in documentation -
The iterators returned by all of this class's "collection view
methods" are fail-fast: if the map is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove method, the iterator will throw a
ConcurrentModificationException. Thus, in the face of concurrent
modification, the iterator fails quickly and cleanly, rather than
risking arbitrary, non-deterministic behavior at an undetermined time
in the future.
How to solve this -
you must change the change the structure of this map while iterating, you can insert this values later, like keep a temporary map and add this to the main map once iteration is finished his job.
Map<Long, Integer> tempMap = new HashMap<>();
for (Map.Entry<Long, Integer> e : map.entrySet()){
map.remove(k);
tempMap.put(x, value);
}
map.putAll(tempMap);
Iterate over a copy and you can add/remove just fine:
for (Map.Entry<Long, Integer> e : new LinkedHashMap<Long, Integer>(map).entrySet()){
map.remove(k);
map.put(x, value);
}
It's not even any more lines of code, because the copy ims made in-line via the copy constructor. LinkedHashMap was chosen to preserve iteration order (if that matters).
A sample code snippet for removing an element from the map is given below.
for(Iterator<Map.Entry<Long, Integer>> it = map.entrySet().iterator();it.next();)
{
Map.Entry<String, String> entry = it.next();
if(//some logic)
it.remove();
}
If your code involves a lot of addition and removal , you might just want to use ConcurrentHashMap.ConcurrentHashMap
You will have to create a copy of your map using copy constructor. Now iterate on 1 and modify second map.
I am assuming that you will not need to iterate newly added value as it wont make much sense.
You can achieve your task by creating a copy is because the keys will remain same in both.
EDIT:
I dont think its a good idea to iterate the newly added element to a Hashmap. If you check the api's provided by Iterator then you will find only remove method, there is no add method in it. There is a reason behind this and you can check javadoc for this.
Now coming to the point, on how to iterate newly added element.
Create a copy of your HashMap. So you will iterate one and modify the the other Map.
As the requirement is to both add and remove elements in Map, i would like to use ListIterator for this [this is different from normal Iterator].
I will get the keyset of Map1 and convert it to a list using ArrayList(Collection<? extends E> c).
Now i will get ListIterator from List created in step 3, and add, remove elements in ListIterator as well as in Map2 [Remeber you need to add , remove both in ListIterator and Map2].
Because you can't do that.
An easy solution is to use another temporary map where you put the values you want and finally switch pointers with the original one (i.e Map = newMap )
Try going through the map as follows
while (tree_map.size() > 0){
// if k is key
if (tree_map.containsKey()){
tree_map.remove(k);
}
tree_map.put(x, value);
break;
// can go through the for loop or other code as per requirements
}

Null pointer exception - iterating over FastMap values

I need to iterate on FastMap.values.
My problem is that basic loop fails over NullPointerException
basic loop
Collection<Order> orders = myObject.getOpenOrders();
for (Order order : orders) {
}
problem is that another thread in my system edits the fastmap
It is adding and removing elements to it and I get the NullPointerException.
Rarely, but It should be solved.
So i added Null check
Collection<Order> orders = myObject.getOpenOrders();
for (Order order : orders) {
if (order != null )
}
and still I get the NullPointerExcetion
So I tried iterate it as follows
FastMap<String, Order> openOrders = myObject.getOpenOrdersMap();
for (FastMap.Entry<String, Order> e = openOrders.head(), end = openOrders.tail(); (e = e.getNext()) != end && e != null;) {
Order order = e.getValue();
}
But then the loop stops when it gets to null instead of throwing NullPointerExcetion.
And this is also a problem, since I need to iterate all of the elements.
I assume that the problem is that the for iteration uses values() and it is actually a pointer to the list.
I tried to copy the list but then I also get NullPointerExcetion in the copy process.
any sugggestions
BTW: I know that changing the whole design is the best solution and using locks in every insert and read. but is there some smaller change I can make in order to solve my problem?
Any idea?
This is not JDK classes? (Javolution?)
From what doc says :
If the map is marked shared then all operations are thread-safe
including iterations over the map's collections
So you may encounter some concurrency problem ?
Try that :
FastMap<String, Order> openOrders = myObject.getOpenOrdersMap().shared()
If you have a multi threaded environment you MUST absolutely use some synchronization, especially when working with iterators.
You cannot iterate a collection while another thread is editing it, this will invalidate iterators and break everything.
So swallow the pill and use some synchronization, this situation requires it.

Categories

Resources