This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 5 years ago.
I am trying to make a simulation of a program which simulates different threads removing and adding objects in an ArrayList. However, late in the simulation I get concurrentModificationExceptions (when the threads are trying to access and modify the same variable while an iterator is being used to iterate through the data). I have searched it up and seen some topics about this saying that I needed to use locks/synchronization and/or using ListIterators instead of enhanced for-loops, however, none of these options seemed to fix the problem. Here is what I have tried to do so far:
public Object removeSomething1(){
synchronized(this){ //Also tried only putting it around the remove block
for(Object o : myList){
myList.remove(o);
return o;
}
}
}
//This is another variaton which did not yield any improved result
public Object removeSomething2(){
ListIterator<Object> iter = myList.listIterator();
While(iter.hasNext()){
Object s = iter.next();
synchronized(this){
iter.remove();
}
return s;
}
}
//After some request here is also the simple code which adds to the list
public addSomething(Object o){
myList.add(o);
}
I execute 5 threads which calls upon these methods in their run() method in an interval of 500ms (using Thread.sleep()). If I increase the sleep timer in each thread and put a Thread.sleep() between each instanciation of threads, the problem seems to go away, but I want the threads to run at (closely) the same time without them interfering with the iterator at the same time which envokes the ConcurrentModificationException.
After a suggestion from the user Louis Wasserman, I move the synchronized block to contain all of removeSomething2(). This makes sense as it now only let's one thread do the whole iteration at a time. This is how the solution looks:
public Object removeSomething2(){
synchronized(this){
ListIterator<Object> iter = myList.listIterator();
While(iter.hasNext()){
Object s = iter.next();
iter.remove();
return s;
}
}
}
Related
If I have an Iterator shared among multiple threads, with each thread calling:
// Inside a thread
int myValue = iterator.next();
what is a possible outcome?
(Ignoring the fact that next() may throw a NoSuchElementException) If the iterator is an iterator over an ArrayList, is it possible that multiple threads may end up with the same value inside the myValue variable?
Is the code below one way to resolve this? (apart from using Java 8 streams as described here Passing a List Iterator to multiple Threads in Java).
// Inside a thread
int myValue;
synchronized(iterator)
{
myValue = iterator.next();
}
TLDR; Never share Iterators between Threads!
Considering the most common use of an iterator for looping over content, you will likely encounter the following snippet:
while(iterator.hasNext()) {
Object nextItem = iterator.next();
}
Now consider the possibility that another Thread performs the exact same operations. Since you cannot control Thread scheduling, the following may happen on an Iterator with a single element:
Thread 1: hasNext? true
Thread 2: hasNext? true
Thread 1: next() //but if this was the last element...
Thread 2: next() //...this will throw NoSuchElementException
Iterators may also support Iterator.remove(), which can lead to ConcurrentModificationException when you operate on shared Collections.
Can we end up with the same value in different Threads?
In a similar fashion to the above, consider this very simple Iterator implementation (simplified code):
class SimpleIterator implements Iterator {
ArrayList source;
int currentIndex;
hasNext() {
return currentIndex<source.size();
}
next() {
Object o = source.get(currentIndex);
currentIndex++;
return o;
}
}
here we may end up with:
Thread 1: get(currentIndex) //Object A
Thread 2: get(currentIndex) //also Object A
Thread 1: currentIndex++
Thread 2: currentIndex++ //you have skipped an element
The answer here is yes, but it's important to note that it very much depends on the implementation. It's much safer not to go there at all.
Repeat: In general you should never share Iterators between Threads.
Is it that multiple threads may end up with the same value inside the
myValue variable?
It's not guaranteed.
Since iterator is not thread-safe, you should synchronize on the collection's object e.g.
Iterator<String> iterator = obj.iterator();
synchronized (obj) {
while (iterator.hasNext()) {
int myValue = iterator.next();
//...
}
}
The behaviour of List#iterator() is inconsistent across List implementations.
ArrayList, LinkedList, will throw ConcurrentModificationException if modified during iteration. To avoid this use a synchronizedList() and lock the List during iteration.
Vectoris synchronized by deafult but the Iterator is not thread safe.
CopyOnWriteArrayList, we can iterate the List safely, even if concurrent modification is happening while iteration.
I'm getting ConcurrentModificationException, so i decided to try something new.
I have an ArrayList of points, which is used in Recycler View for download all graphs in parallel threads.
Is it possible to lock this downloads, when i'm writing to ArrayList and not having a chain download later?
Because now i'm using this in my Fragment:
public static final Object lock = new Object();
synchronized (lock) { /*download and write to ArrayList*/ }
And in every Cell i want to use
synchronized (lock) { /*download graphs*/ }
And i think when one cell is loading graph, all will wait, then second will load and so on.
ConcurrentModificationException usually indicates that a collection was modified while an iterator was in progress. It's not necessarily in a different thread :
List<Object> someList = new ArrayList<>();
someList.add("an item");
for (Object item : someList) {
// throws ConcurrentModificationException
someList.add("a new item");
}
It's difficult to know what really happen in your case. What happen if you replace ArrayLists with CopyOnWriteArrayList ? They are much less efficient than ArrayLists but it probably doesn't matter, at least compared to network operations.
I am using the listIterator() for accessing and removing items from a LinkedList in a class that implementsRunnable I am also modifying values of this list in some other part of the program concurrently.
Where I am using listIterator() in this part of the code I am getting ConcurrentModificationException from this function call:
java.util.LinkedList$ListItr.checkForComodification
Why do I get this and how do I prevent it?
#Override
public void run()
{
while(true)
{
itr = nodeAttributes.listIterator();
while (itr.hasNext())
{
System.out.println("enterred");
nodeAttribute nA = (nodeAttribute) itr.next();
//System.out.println("for");
if(!nA.isMoving && !nA.moveQueue.isEmpty())
{
if(animator != null)
animator.stop();
animator = (Animator) nA.moveQueue.poll();
//itr.remove();
animator.start();
nA.isMoving = true;
System.out.print( "animator");
}
}
System.out.println( "looping");
}
}
Your post doesn't have a question, just a statement. However what you describe is the expected behaviour. From the docs:
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the Iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException.
So to prevent this you need to prevent modification by a writer at the same time as a reader is iterating. Use the Collections.synchronizedList method. All access (readers and writers) should follow this pattern:
// store a single synchronized list reference for all access to use
nodeAttributes = Collections.synchronizedList(theLinkedList);
and then all readers and writers should use a synchronized (list) block.
// Readers might do:
synchronized (list) {
itr = nodeAttributes.listIterator();
while (i.hasNext())
... do stuff ...
}
Those threads that operate without iterating can just use the "atomic" methods on the return object from Collections.synchronizedList, such as add. These methods use a sync block under the covers, so they are just a shorthand and they will still block the thread while another is in a sync block.
There are many, many ways to deal with concurrent reader and writers.
One is the above, but it may lock out other threads for a long time while each iterator does it's stuff.
Another is to copy the list to an array (inside a synchronized section) and then read the array outside the lock.
Yet another would be to use a ReadWriteLock.
and there are more options, all dependent on your exact use case.
this is a follow-up post to Do I need a concurrent collection for adding elements to a list by many threads?
everybody there has focused on expaning of the list. I understand how that can be a problem, but .. what about adding elements ? is that thread-safe?
example code
static final Collection<String> FILES = new ArrayList<String>(1000000);
and I execute in many threads (I add less than 1000000 elements)
FILES.add(string)
is that thread safe ? what are possible problems with doing it that way ?
ArrayList<String> is not synchronized by itself. Use Collections.synchronizedList(new ArrayList<String>()) instead.
use Collections.syncronizedList(new ArrayList<String>(1000000))
Even if the list doesn't expand, it maintains its internal state, such as the current size. In a wider sense, ArrayList is specified a mutable object which is not thread-safe, therefore it is illegal to concurrently call any mutator methods on it.
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
This is the source cod of the ArrayList in 7u40-b43.
The method ensureCapacityInternal() is not thread safe,and size++ is not either.
The size++ is done by three steps,1)get the size,2) size +1,3) write the new value back.
I'm creating a Swing application to make a Game with. It creates images in random locations off the screen and when they leave the screen I would like to remove them. Please take a look at the code snippet:
public void checkTrolls(){ //CAUSES EXCEPTION ERROR WHEN SPRITE EXIT SCREEN
for(AutomatedSprite a : trolls){
if(a.getX() < 0 - a.getImage().getWidth())
trolls.remove(a);
if(a.getY() < 0 - a.getImage().getWidth())
trolls.remove(a);
if(a.getX() > 800)
trolls.remove(a);
if(a.getY() > 600)
trolls.remove(a);
}
}
#Override
public void run() {
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while(true){
dodger.update(); //update sprite
if(trolls.size() != 6){
trolls.add(new AutomatedSprite("images/troll_face.png"));
}
for(Sprite troll : trolls){
troll.update(); //UPDATES MY SPRITES
}
checkTrolls(); //CHECKS TROLLS EXITING THE SCREEN
repaint();
for(Sprite troll : trolls){
System.out.println("X: " + troll.getX());
System.out.println("Y: " + troll.getY());
}
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = timeDiff - DELAY;
if(sleep < 0)
sleep = 5;
try {
Thread.sleep(sleep);
} catch (InterruptedException e) { e.printStackTrace(); }
beforeTime = System.currentTimeMillis();
}
}
trolls is a Vector of AutomatedSprites, when they leave the screen I get a ConcurrentModificationException, apparently I can't remove the instances from my vector.
So it seems that I can't remove anything from the vector while the thread is updating all my sprites, is there a way to pause my thread so I can remove the sprite?
P.S: here is the entire class in case I missed something: Pastebin
You cannot remove from a collection while iterating over it, this is true for a single threaded environment as well as a multithreaded one. syncrhonized will still cause the issue, Thread.sleep too. Use and Iterator and remove that way.
public void checkTrolls(){
for(Iterator<AutomatedSprite> itr = trolls.iterator(); itr.hasNext();){
AutomatedSpring nextElemnt = itr.next();
if(youShouldRemoveTheSprite){
itr.remove();
}
}
}
So here you use the Iterator supplied by your trolls collection. And you are asking the Iterator to safely remove the object from the collection.
Now if you are executed checkTrolls with multiple threads then you will need to synchronize. You can do that like this
public synchronized void checkTrolls(){ ...
Edit based on your recent comment/link.
It isn't so much you assigning the Iterator.next() to a variable, its that you are invoking iterator.next() many times. Each time you invoke next() you are moving the iterator to the List's next element. So at the end of one loop iteration you move the iterator to the 6'th element in the list. If you were indexing it instead it would look like:
for(Iterator<AutomatedSprite> itr = trolls.iterator(); itr.hasNext(); ){
if(trolls.get(0).getX() < 0 - trolls.get(1).getImage().getWidth() ||
trolls.get(2).getY() < 0 - trolls.get(3).getImage().getWidth() ||
trolls.get(4).getX() > 800 ||
trolls.get(5).getY() > 600){
trolls.remove(trolls.get(5));
}
Note for this example: indexing at 0,1,2,3,4... is only for demonstration, in practice it would be i = 0; start for loop trolls.get(i++).getX(), trolls.get(i++).getY() and so forth. If your list was 10,000 you would eventually get a NoSuchElementException
So for example, if you only have 3 trolls, once you get to the 4th itr.next() you'll get a NoSuchElementException. For that reason you'll want to store the next() element in a variable and work on that variable so the itr.hasNext(); returns correctly and the itr.remove() too works correctly.
In checkTrolls() you are removing elements from your Vector as you iterate over it. This will cause a ConcurrentModificationException
From Vector's javadoc
The iterators returned by this class's iterator and listIterator
methods are fail-fast: if the vector is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove or add methods, the iterator will throw a
ConcurrentModificationException.
A couple alternatives:
Create a list of elements to remove and remove them after iterating fully.
Use a thread safe List implementation such as CopyOnWriteArrayList
Have your code inside run method in synchronized block. synchronized will make sure only one thread executing your code at a time.
run(){
synchronized(this){
....your code.
}}
You may make run() also synchronized.
A simple and somewhat naive solution would be too simply synchronize on the trolls collection. If you do this, make sure to yield in the Animator thread to give your checkTrolls function a chance to do processing and cleanup.
I think the problem might be that in 'checkTrolls' you're trying to modify a vector over which you're iterating.