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
Related
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.
Now that I have a handle on retrieving objects in parallel, how can I add those objects to a list?
I have a list of Future<Site> objects that I'm attempting to add to an ArrayList of Site objects. Here's my for loop. I can add a print statement in the loop and it reveals that the list of Future<Site> objects is indeed populated, however adding to the existing list (last line) does not work.
List<Future<Site>> futures=threadmaker.invokeAll(active_sites.stream().map(site -> new TAG_SCANNER(site, loggr)).collect(Collectors.toList()));
//Now fetch all the results
for (Future<Site> result : futures) {
//SOUND THE ALARMS (adding to existing list)
alarm_sites.add(result.get());
}
EDIT:
I thought Future's get method was blocking, in that the code would not progress until it returns a result. Does my mistake lie in trying to add to an already existing list?
For some reason, creating the list after my invokeall command solved my issues. I'm not sure why the pre-existing list didn't work but I'm marking the issue as solved for now, and I'll look into this later to see what may have happened.
I have the following situation:
In a main function if some controller class I retrieve 10 product objects from my DB. These are hold in an ArrayList object.
Afterwards I create three classes which extend Runnable and I give to each class the product-ArrayList into the constructor.
In each of the constructors is a new local ArrayList created and the objects in the product-ArrayList are added:
this.products = new ArrayList();
products.addAll(productListParam);
Afterwards I start each of three threads and they iterate over their local products-lists and also modify it.
I'm getting a ConcurrentModificationException while iterating over the local product ArrayList..
Why is this happening? I was assuming that if I create a complete new list in each thread I can modify this locally as much as I want without caring about the other threads - am I right? Or does the removal of some object from a local list affect the pbjects somehow so that the other threads throw the Concurrent Modification Exception?
Actually the stacktrace looks like:
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at com.x.y.class.method(Classname.java:326)
and Classname.java at 326 looks like:
325:List<Product> productsToDelete = new ArrayList();
326:for(Product p: products){
...
if(xy){
productsToDelete.add(p);
}
}
products.removeAll(productsToRemove);
Maybe someone has a hint for me what I'm doing wrong?
Edit: Inside the loop the product object p is just used for reading. Additionally there are no modifications done to the products-ArrayList. They are only added to a second "toBeRemoved" list to remove them later after the for-loop finished.. I edited the code above.
I think I'm mostly interested in the question if I can create several list-objects, add the same product-objects to each of them via the addAll()-method and then can to anything with it in each thread without caring about the other threads?!
You can't modify the Collection inside an enhanced for loop that iterates over its elements. Not even if you only have a single thread.
You didn't include the code inside the enhanced for loop, but if what you need to do inside it is remove elements from the list, you can use an explicit iterator.
Iterator<Product> iter = products.iterator();
While (iter.hasNext() {
Product p = iter.next();
....
if (some condition)
iter.remove();
....
}
Sorry guys to bother you, I did a bad beginner fault!
I was setting the mentioned product-ArrayList manually later from some other code basis and did overwrite the new ArrayList.. so all threads again used only one ArrayList and the ConcurrentModificationException occured.
As you see within this example, always double check your code :)
Sorry for bothering you..
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
I'm iterating over a JRE Collection which enforces the fail-fast iterator concept, and thus will throw a ConcurrentModificationException if the Collection is modified while iterating, other than by using the Iterator.remove() method . However, I need to remove an object's "logical partner" if the object meets a condition. Thus preventing the partner from also being processed. How can I do that? Perhaps by using better collection type for this purpose?
Example.
myCollection<BusinessObject>
for (BusinessObject anObject : myCollection)
{
if (someConditionIsTrue)
{
myCollection.remove(anObjectsPartner); // throws ConcurrentModificationException
}
}
Thanks.
It's not a fault of the collection, it's the way you're using it. Modifying the collection while halfway through an iteration leads to this error (which is a good thing as the iteration would in general be impossible to continue unambiguously).
Edit: Having reread the question this approach won't work, though I'm leaving it here as an example of how to avoid this problem in the general case.
What you want is something like this:
for (Iterator<BusinessObject> iter = myCollection.iterator; iter.hasNext(); )
{
BusinessObject anObject = iter.next();
if (someConditionIsTrue)
{
iter.remove();
}
}
If you remove objects through the Iterator itself, it's aware of the removal and everything works as you'd expect. Note that while I think all standard collections work nicely in this respect, Iterators are not required to implement the remove() method so if you have no control over the class of myCollection (and thus the implementation class of the returned iterator) you might need to put more safety checks in there.
An alternative approach (say, if you can't guarantee the iterator supports remove() and you require this functionality) is to create a copy of the collection to iterate over, then remove the elements from the original collection.
Edit: You can probably use this latter technique to achieve what you want, but then you still end up coming back to the reason why iterators throw the exception in the first place: What should the iteration do if you remove an element it hasn't yet reached? Removing (or not) the current element is relatively well-defined, but you talk about removing the current element's partner, which I presume could be at a random point in the iterable. Since there's no clear way that this should be handled, you'll need to provide some form of logic yourself to cope with this. In which case, I'd lean towards creating and populating a new collection during the iteration, and then assigning this to the myCollection variable at the end. If this isn't possible, then keeping track of the partner elements to remove and calling myCollection.removeAll would be the way to go.
You want to remove an item from a list and continue to iterate on the same list. Can you implement a two-step solution where in step 1 you collect the items to be removed in an interim collection and in step 2 remove them after identifying them?
Some thoughts (it depends on what exactly the relationship is between the two objects in the collection):
A Map with the object as the key and the partner as the value.
A CopyOnWriteArrayList, but you have to notice when you hit the partner
Make a copy into a different Collection object, and iterate over one, removing the other. If this original Collection can be a Set, that would certaily be helpful in removal.
You could try finding all the items to remove first and then remove them once you have finished processing the entire list. Skipping over the deleted items as you find them.
myCollection<BusinessObject>
List<BusinessObject> deletedObjects = new ArrayList(myCollection.size());
for (BusinessObject anObject : myCollection)
{
if (!deletedObjects.contains(anObject))
{
if (someConditionIsTrue)
{
deletedObjects.add(anObjectsPartner);
}
}
}
myCollection.removeAll(deletedObjects);
CopyOnWriteArrayList will do what you want.
Why not use a Collection of all the original BusinessObject and then a separate class (such as a Map) which associates them (ie creates partner)? Put these both as a composite elements in it's own class so that you can always remove the Partner when Business object is removed. Don't make it the responsibility of the caller every time they need to remove a BusinessObject from the Collection.
IE
class BusinessObjectCollection implements Collection<BusinessObject> {
Collection<BusinessObject> objects;
Map<BusinessObject, BusinessObject> associations;
public void remove(BusinessObject o) {
...
// remove from collection and dissasociate...
}
}
The best answer is the second, use an iterator.