Solving a ConcurrentModificationException - java

I am writing a little game which has many circles moving on the screen.
I am managing the circles in two threads as following:
public void run() {
int stepCount = 0;
int dx;
int dy;
while (m_threadTrap){
dx = 0;
dy = 0;
synchronized (m_circles) {
for (Iterator<Circle> it = m_circles.iterator(); it.hasNext();){
Circle c = it.next(); //Exception thrown here.
if (c.getDirX() != 0)
if (stepCount % c.getDirX() == 0){
dx = 1;
}
if (c.getDirY() != 0)
if (stepCount % c.getDirY() == 0){
dy = 1;
}
c.move(dx, dy);
}
}
if (stepCount == 150000){
stepCount = 0;
}
stepCount++;
}
}
m_circles in an ArrayList of Circles.
And the following Thread:
public void run() {
while (m_threadTrap){
int topPosition;
int bottomPosition;
int leftPosition;
int rightPosition;
ArrayList<Circle> removedCircles = new ArrayList<Circle>();
synchronized (m_circles.getCircles()) {
for (Iterator<Circle> it = m_circles.getCircles().iterator(); it.hasNext();){
Circle c = it.next();
// Some calculation to evaluate which circles should be removed
removedCircles.add(c);
}
}
}
try{
Thread.sleep(25);
}
catch (Exception e) { }
m_circles.getCircles().removeAll(removedCircles);
if (m_circles.getCircles().size() < 30)
m_circles.addNewCircle();
repaint();
}
}
My problem is that I get ConcurrentModificationException at the line
Circle c = it.next();
in the first thread. At first I tried going over the ArrayList with a foreach loop and this gave me the same exception.
After researching a bit on this exception I saw two solutions:
1. Putting the part which accesses the collection in a synchronized block.
2. Using the Iterator object of the collection.
Neither of them solved it for me.

For a synchronized() {} block to be effective, all accesses to the protected objects must be wrapped in synchronized blocks. You probably forgot to wrap some access.
Another "gotcha" is that ConcurrentModificationException can also mean that it was concurrently modified in the same thread. For example, if you remove an element from a collection while traversing it, you may get this exception. (As an exception, you can safely remove elements via the iterator itself)

ConcurrentModificationException means that you are iterating over a collection and, while iterating, someone (the current thread or another one) modified the underlying collection without using Iterator.remove(). Whenever you invoke an operation on the Iterator it checks that the underlying collection has not been changed. Using a foreach does not change a thing, since it uses an Iterator to perform the loop.
Your solution are:
create a new collection:
for (Circle c: new ArrayList(m_circles.getCircles()).iterator()) {
// Some calculation to evaluate which circles should be removed
removedCircles.add(c);
}
or synchronize both threads on the same object (you synchronize on different objects, therefore it does not do anything) whenever you are modifying or accessing the collection

Related

Is it safe clear a Set in a loop if it finds the correct value?

I'm in this situation: if I find a specific value in a HashSet, I have to update a field, clear the set and return the field.
Here one example:
static Set<Integer> testSet = new HashSet<>();
static Integer myField = null; // the field could be already != null
public static int testClearSet()
{
for (int i = 0; i < 100; i++) { // this is just for the test
testSet.add(i);
}
for (Integer n : testSet) {
if (n == 50) {
myField = n;
testSet.clear();
return myField;
}
}
return -1;
}
I'm wondering if doing this to the set it's safe, considering the fact that later on I should reuse the set.
I'm asking this, because I knew that to make changes over a Collection while iterating, is not a "good practice", but this case I think is a little bit different.
A possible solution would be:
boolean clear = false;
for (Integer n : testSet) {
if (n == 50) {
myField = n;
clear = true;
break;
}
}
if (clear) {
testSet.clear();
return myField;
}
So, which one is the right way?
It should be safe to remove elements from a set when using an explicit iterator. Hence the following should be safe:
Iterator<Integer> iterator = testSet.iterator();
while (iterator.hasNext()) {
Integer element = iterator.next();
if (element.intValue() == 50) {
testSet.clear();
break;
}
}
A ConcurrentModificationException is only thrown if you continue iterating after changing it manually.
What you do is change it and abort iterating, so it should be 100% safe (regardless of the for-each implementation).
The real issue is, the readability of the code. A piece of code should ideally do one job, and if this job is complicated, split it up. In particular, your code has two parts, a condition and an action:
if (some condition) do some action
So:
public static int testClearSet() {
if (setConatins(50)) {
myField = 50;
testSet.clear();
return myField;
}
return -1;
}
private static boolean setConatins(int searchFor) {
for (Integer n : testSet) {
if (n == searchFor) {
return true;
}
}
return false;
}
The latter method can be replaced with a single API call, for you to figure out.
If you know that your Set changing only in one thread, so you can clean it like in first example.
Method clear() does not throw ConcurrentModificationException.
Both your code will work.
There is indeed a restriction in modifying the collection when u iterate using fail fast iterators. That means, iterating using fail fast iterator will fail if there is any modification in the collection after the iterator was created. All the default iterators that is returned by java collection classes are fail-fast iterators.
private void removeDataTest (Collection<String> c, String item) {
Iterator<String> iter = c.iterator(); //Iterator is created.
while (iter.hasNext()) {
String data = iter.next();
if (data.equals(item)) {
//c.remove(data); //Problem. Directly modifying collection after this iterator is created. In the next iteration it will throw concurrent modification exception.
iter.remove(); //This is fine. Modify collection through iterator.
//c.clear(); break; //This is also should be okay. Modifying the collection directly, but after that it is breaking out and not using the iterator.
}
}
}
In your code, u don't continue iteration after the set is modified. So should be fine.

Unclear ConcurrentModificationException on separate lists

in a class I've those 2 methods:
public void notifyResult(List<Road> result) {
ArrayList<RoadOverlay> tempRoads = new ArrayList<>();
for(Road road:result){
// Computes and stores the overlays
// ...
tempRoads.add(new RoadOverlay());
}
//switch field when update is done
this.positions = tempRoads;
}
}
private void drawRoadsVO(GL gl) {
// keep a reference on the current instance of the field
// to avoid concurrent modification in notifyResult
ArrayList<RoadOverlay> positionsCopy = this.positions;
int vertexCount = 0;
for (RoadOverlay road : positionsCopy) { //ConcurrentModificationException here
// ...
}
}
Both method run in separate threads. Inside rendering i make no change on the list, and to my understanding i work on separate lists so how could this produce CME?
I'm struggling on this one, and any clue would be welcome. As far as possible I try to avoid penalty of using synchronisation.
regards
Edited a comment in the code
It is usually better to make full copy of a list
ArrayList<RoadOverlay> positionsCopy = new ArrayList<Integer>(this.positions);
As for ConcurrentModificationException, your code looks fine, may be you are modifying current this.positions in some other class methods?
Note that your this.positions variable should be declared as volatile.
Here is next() method of ArrayList iterator
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
ConcurrentModificationException could be thrown only in case then list's elementData is structurally modified
Structural modifications are those that change the size of the list,
or otherwise perturb it in such a fashion that iterations in progress
may yield incorrect results.
the problem is inside drawRoadsVO method your var positionsCopy is not actually a copy, but a reference to the same object this.positions.
In order to make actual copy you should do
ArrayList<RoadOverlay> positionsCopy = new ArrayList(this.positions);

ArrayList.addAll() ConcurrentModificationException

I'm facing some really strange problems while implementing a kind of Kademlia bucket in Java 8 (OpenJDK).
I need to get at least a specific number of items from so-called Buckets.
But that's not the problem.
Somehow, I get sometimes a ConcurrentModificationException while doing closest.addAll() on the ArrayList though it is just used in a single thread and I'm not iterating or doing something like that.
Do you know how to help me?
Here is my code (I know it's a mess!):
List<Neighbour> getClosest(Node n, int num) {
ArrayList<Neighbour> closest = new ArrayList<>();
int missing;
int walkDown = n.getBucket(me);
int walkUp = walkDown + 1;
boolean pleaseBreak = true;
while (true) {
missing = num - closest.size();
if (missing <= 0) {
return closest;
}
if (walkUp >= 0 && walkUp < 160) {
List<Neighbour> l = buckets[walkUp].getClosest(missing);
closest.addAll(l);
if (closest.size() >= missing) {
return closest;
}
walkUp++;
pleaseBreak = false;
}
if (walkDown >= 0 && walkDown < 160) {
List<Neighbour> l = buckets[walkDown].getClosest(missing);
closest.addAll(l);
if (closest.size() >= missing) {
return closest;
}
walkDown--;
pleaseBreak = false;
}
if (pleaseBreak) {
return closest;
}
pleaseBreak = true;
}
}
ConcurrentModificationException actually means that you are breaking the rules of iteration by somehow modifying the list while iterating it.
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.
That said it is fairly clear what could be causing this issue. As closest is a new List being filled by the method it must be l that is being modified.
There are two options:
Another thread is doing it.
You already have an iterator open across the list l.
Assuming it is not 1 (or you would probably have mentioned that) I will go for:
Your getClosest method is returning a sublist of a list that is being iterated across and/or modified and addAll is also attempting to iterate over it.
To fix, make getClosest return a copy of the sublist.

Maintain order of Arraylist in multiple threads

How can I make sure the print out order same as the order in the original array, when two threads are used? I want it printing '0 1 2 3 4 5 6 7 8 9', but currently the order is not guaranteed. Any way to make it in order? Thank you a lot.
public class Test {
public static void main(String[] args){
DataStore dataStore = new DataStore();
for(int i=0; i<10; i++){
dataStore.add(String.valueOf(i));
}
CopyThread t1 = new CopyThread(dataStore);
CopyThread t2 = new CopyThread(dataStore);
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch(Throwable t) {
}
}
}
class CopyThread extends Thread {
private DataStore data;
public CopyThread(DataStore data){
this.data = data;
}
public void run(){
DataStore.Line line = null;
int lineID;
while( (line = data.getLine()) != null ){
lineID = line.id;
System.out.println(Thread.currentThread().getName() + ": " + lineID);
}
}
}
class DataStore {
ArrayList<String> lines = new ArrayList<String>();
int current = 0;
public synchronized Line getLine () {
if (current >= lines.size()) {
return null;
}
Line line = new Line(lines.get(current), current);
current++;
return line;
}
public synchronized void add (String s) {
lines.add(s);
}
public synchronized int size () {
return lines.size();
}
public static class Line {
public String line;
public int id;
public Line (String str, int i) {
line = str;
id = i;
}
}
}
Try Vector instead of ArrayList .
Vector
The Vector class implements a growable array of objects. Like an
array, it contains components that can be accessed using an integer
index. However, the size of a Vector can grow or shrink as needed to
accommodate adding and removing items after the Vector has been
created.
Each vector tries to optimize storage management by maintaining a
capacity and a capacityIncrement. The capacity is always at least as
large as the vector size; it is usually larger because as components
are added to the vector, the vector's storage increases in chunks the
size of capacityIncrement. An application can increase the capacity of
a vector before inserting a large number of components; this reduces
the amount of incremental reallocation.
The Iterators returned by Vector'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. 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. The Enumerations returned by Vector's elements method
are not fail-fast.
Note that the fail-fast behavior of an iterator cannot be guaranteed
as it is, generally speaking, impossible to make any hard guarantees
in the presence of unsynchronized concurrent modification. Fail-fast
iterators throw ConcurrentModificationException on a best-effort
basis. Therefore, it would be wrong to write a program that depended
on this exception for its correctness: the fail-fast behavior of
iterators should be used only to detect bugs.
You can use synchronize to achieve that:
synchronized(data) {
while( (line = data.getLine()) != null ){
lineID = line.id;
System.out.println(Thread.currentThread().getName() + ": " + lineID);
}
}

concurrentexception i don't understand where it's the error

I receive this exception
Exception in thread "Thread-3" java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:761)
at java.util.LinkedList$ListItr.next(LinkedList.java:696)
at ServerMultiThread.run(ServerMultiThread.java:89)
at java.lang.Thread.run(Thread.java:680)
from this code:
synchronized(itemsList)
{
if(itemsList.isEmpty())
{
item.initCounter();
itemsList.add(item);
pw.println("It's the first time you connect to server!");
}
else
{
for(ItemClient itm : itemsList)
{
if(itm.equals(item))
{
int value = itm.getCounter();
value++;
itm.setCounter(value);
pw.println(itm.getCounter());
}
else
{
item.initCounter();
itemsList.add(item);
pw.println("It's the first time you connect to server!");
}
}
}
}
the row 89 corresponds to this for(ItemClient itm : itemsList). Why I receive this error?
You are changing the LinkedList content inside the for-each loop. The implementation of the LinkedList iterator checks on the next call to next() if the list has changed and throws the exception (sad I know ...).
The enhanced for loop is used to iterate over the given set of values, but during iteration you are modifying the contents of the same, that's why you getting that error, instead use a normal for loop to do your stuff for this thing.
Regards
Sadly, there is no easy way around it. As the others have said, you cannot modify a collection inside this kind of loop. Your other option is to use a normal for loop. However, accessing a LinkedList by index like:
for(int i = 0; i < list.size(); i++) {
list.get(i);
}
takes O(N) time for each item, because the linked list needs to be traversed from the beginning each time.
If the linked list is not essential to your algorithm, I suggest you to use an ArrayList instead and change your code as follows:
for(int i = 0; i < itemsList.size(); i++) {
itm = itemsList.get(i);
if(itm.equals(item)) {
int value = itm.getCounter();
value++;
itm.setCounter(value);
pw.println(itm.getCounter());
} else {
item.initCounter();
itemsList.add(item);
pw.println("It's the first time you connect to server!");
}
}
This will not throw the exception, but it's still not a nice piece of code because you are adding to the list while iterating and that is never a good idea.
I hope you had patience to read so far!
My final suggestion for you is to hold a temporary list of elements that you need to add and append them to the initial list at the end of the loop. This way you can keep all your original code and the LinkedList:
LinkedList<ItemClient> tempList = new LinkedList<ItemClient>();
for(ItemClient itm: itemsList) {
itm = itemsList.get(i);
if(itm.equals(item)) {
int value = itm.getCounter();
value++;
itm.setCounter(value);
pw.println(itm.getCounter());
} else {
item.initCounter();
tempList.add(item);
pw.println("It's the first time you connect to server!");
}
}
itemsList.addAll(tempList);

Categories

Resources