Java: ConcurrentModificationException, 3 threads, different lists, same objects - java

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..

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

Java: Adding Future<obj> to a list

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.

Synchronization on Collections.unmodifiableList

I have a question. I think i know the answer but for some reason i prefer to ask for it here.
So here is the scenario:
I have an Object which has a list as a field. Then i have a method that returns the list as an unmodifiableList.
The Oject class has other methods that add elements to the list.
So lets imagine a case where one thread is iterating throught the unmodifiable list and another thread that is adding elements to the list using the Object class method.
How do i make this thread safe? If i synchronize the unmodifiableList and the list itselft will it make it thread safe? After all they are two different object where the unmodifiableList has a field which is the naked list itselft.
You need to make the "naked" list synchronized:
private List<Foo> list = Collections.synchronizedList(new ArrayList<Foo>());
But beware: that will only make sure the list internal state is coherent. As soon as you iterate on the list, you can't prevent a modification to the list to happen between two calls to the list iterator. So nothing will prevent a ConcurrentModificationException to happen in that case. To prevent that, you should not return any reference (even an indirect one) to the list. All modifications and iterations to the list should be encapsulated in your class, and properly synchronized.
You can return an unmodifiable-clone of original list to the caller.
The disadvantage is that the caller may end up with a "stale" version of the list. However, by this way you achieve safe iterations. In concurrent world, it is OK to return last successfully updated data to the caller.
public List<Thing> getThings() {
List<Thing> copytOfThings = new ArrayList<>();
copyOfThings.addAll(_things); //original list items.
return Collections.unmodifiableList(copyOfThings);
}
There are a couple of ways you could do this:
Return a copy of the list, rather than an unmodifiable view of it
Rather than using the iterator, use List.get(int)

Java, remove elements from multiple threads

I have multiple threads iterating over a list. All these threads will in the end find a matching element to remove from such list.
To avoid inconsistent states what should I use for the list? Vector? ArrayList? Other?
Here is an example with Vectors. It doesn't give errors but I'm sure it could:
for(int i=0; i<timersVector.size(); i++){
currTimerThread = timersVector.get(i);
if(currTimerThread.getRowViewTag().equals(parent.getTag())){
currTimerThread.stopTimer();
timersVector.remove(i);
Log.i(tag, "timerVector size: "+timersVector.size());
}
}
For example, if one thread is entering the loop and size is 10 and right after another thread is removing the element at 5, what would happen to the first one?
Thanks for any help
For a Vector each operation is thread safe, however multiple operations are not. As you are performing multiple operations, you need to hold a lock on the collection while performing them all. i.e. outside the loop in this case.
e.g. the element you get(i) and the element you remove(i) could be changed by another thread. There is no guarantee the element you removed is the one you checked.
BTW ArrayList replaced Vector in 1998. I suggest you use that and synchronize as required and/or use Collections.synchronizedList(new ArrayList<>())
Accessing a List from multiple threads requires a synchronized List wrapper. The java.util.Collections utility class contains all kind of synchronized wrappers.
In your case, wrap your list (don't use Vector, it's there of backward compatibility only) using this simple line of code:
List<Timer> timers = Collections.synchronizedList(originalTimers);
Suggestion: Usage of synchornized map would be more efficient in your case and wouldn't require a loop to search through items.

Java serialization causes concurrency modification exception

My program updates several hundred objects stored in an ArrayList about one hundred times per second. I've implemented Java's built in serialization, and it works well except when an attempt to serialize is made when the objects are going at it, in which case I may have to serialize a half dozen times before it works (each failed attempt throws an exception). I tried marking the arraylist as transient, but then when I loaded the serialization file, a null pointer exception is thrown. So I tried initializing the transient arraylist in the no args constructor, which did nothing to help. What do I do? Thanks.
First make sure you've synchronized access to your ArrayList, e.g. when you initialize it:
List<String> list = Collections.synchronizedList(new ArrayList<String>());
When you need to serialize it, grab a copy that will be consistent due to the synchronization:
List<String> copy = new ArrayList<String>(list);
Now you can safely serialize out this copy without blocking access to the primary list.
You can't iterate with foreach statement and modify your table.
Try to use
for (int i =0;i<arra.length;i++)
instead.
Copy the ArrayList to a new instance (shallow copy with new ArrayList<>() and serialize that.
Use the Iterator if you are traversing through the collection and concurrently modifying it.
Assuming you really don't want or need the list contents serialised declare your list member:
private transient final List<?> things = new ArrayList<Object>();
You will always have a non-null list to work with.
That being said, from the sound of it your updates to the list itself may need to be thought about regarding other thread-safety issues such data-races and visibility issues.

Categories

Resources