Hi guys I have a small problem. I'm writing a app for android and I have a part of my code like this.
public void loop(){
for(Car car:carList)
car.run();
}
I got the error java.util.ConcurrentModificationException
I also tried using iterators in order to solve the problem quickly.
Also, I use synchronized since I checked the error in oracle docs and it says that could be caused by many threads using the same code.
public synchronized void loop(){
Iterator<Car> carIterator = carList.iterator();
while(cardIterator.hasNext()){
carIterator.next().run();
}
}
I don't really know why any of the solutions I found didn't work. I use this portion of code most of the cases in a background service and I use it's class that contains that method (using singleton) in the acivity too.
Thanks in advance to all the comunity
Thanks for the support guys,
-carList is a ArrayList of Car objects.
my car class is like this
public class Car{
private int mSpeed;
private int mDistance; //zero at first
........
public void run(){
mSpeed=getRandomSpeed();
mDistance+=mSpeed;
updateDistanceInDB();//here I sabe the distance in DB using a DB helper
}
.........
}
-The error indicates that it's generated in the line that executes the method run
There's something strange because the app works well in another device I have.
The most brute-force way to fix this exception is to use a CopyOnWriteArrayList in place of your current List. This will ensure that any updates to the list during a for-each loop won't be seen during iteration, and therefore won't throw a ConcurrentModificationException.
According to its documentation:
The "snapshot" style iterator method uses a reference to the state of the array at the point that the iterator was created. This array never changes during the lifetime of the iterator, so interference is impossible and the iterator is guaranteed not to throw ConcurrentModificationException.
However, there may be a better way to solve your issue depending on the situation. Look for what parts of your code make modifications to the List, and ensure that they don't run during iteration.
Related
I'm occasionally getting a ConcurrentModificationException when I iterate over a list. A Google search informs me that it's probably because I'm altering that list in another thread while iterating over it and that to make this problem go away I should use java.util.concurrent.CopyOnWriteArrayList....
... except I already am.
Apparently, I'm doing something really stupid somewhere.
Does anybody have any insight into how one might induce CopyOnWriteArrayList to toss a ConcurrentModificationException? If it matters, I'm using Java 5.
Edit: Since the mutators I'm using may matter, I'm modifying this list in two ways:
Adding elements to the front. (list.add(0, newElement);)
Using subList to let older items fall off the back. (list = list.subList(0, MAX_LIST_SIZE);)
Do those raise red flags? If so, why? My understanding was that because these operations make a copy of the thing first, any existing iterators would be pointing at the unmodified original and would thus not care. Do I have a hole in my knowledge?
Edit 2: The precise code that's causing the problem is still a bit murky, but I can at least post the exception I'm seeing:
java.util.ConcurrentModificationException
at java.util.concurrent.CopyOnWriteArrayList$COWSubList.checkForComodification(Unknown Source)
at java.util.concurrent.CopyOnWriteArrayList$COWSubList.iterator(Unknown Source)
at....
... where it points to a for-each loop instantiation in my code.
That COWSubList does seem to imply that my call to subList is the root of my problem; I'd still like to understand why.
Edit 3: *facepalm*
CopyOnWriteArrayList.subList() returns a List, not a CopyOnWriteArrayList. The list it returns is under no implied obligation to provide any of COWAL's protections. Which makes using subList() like this to remove elements a Very Bad Idea.
Don't know for certain if this is my culprit, but it's damned suspicious and needs to be corrected regardless.
CopyOnWriteArrayList.subLists throw ConcurrentModificationExceptions if the containing list changes out from underneath it:
public class ListTest {
private static List<int[]> intList;
public static void main (String[] args) {
CopyOnWriteArrayList<Integer> cowal = new CopyOnWriteArrayList<Integer>();
cowal.add(1);
cowal.add(2);
cowal.add(3);
List<Integer> sub = cowal.subList(1, 2);
cowal.add(4);
sub.get(0); //throws ConcurrentModificationException
}
}
Sbodd has the correct answer, but it sounds like using CopyOnWriteArrayList instead of ArrayList is just an attempt to mask the error. The true problem is an attempt to modify the underlying list while iterating over it. You need to find where in your code you are accessing it as such and remove that usage or work around it.
For example, some method has the next implementation:
void setExcludedCategories(List<Long> excludedCategories) {
if (excludedCategories.contains(1L)) {
excludedCategories.remove(1L);
}
}
And it's called in the next way:
setExcludedCategories(Array.asList(1L, 2L, 3L));
Of course, it will lead ot an exception java.lang.UnsupportedOperationException when it will try to remove item.
The question: how can I modify this code to be sure that the input parameter excludedCategories supports remove?
UPD:
Thanks for answers. Let's summarize results:
Always create new ArrayList from the input list to be sure it's mutable - a lot of useless memory would be used -> NO.
Catch the UnsupportedOperationException.
Specify in the JavaDoc that a caller mustn't pass an immutable list - anybody read the JavaDoc? When something doesn't work only :)
Don't use Arrays.asList() in a caller's code - that's an option, if you an owner of this code, but anyway you should know if this concrete method allows immutable or not (see 3).
It seems the second variant is the only way to resolve this problem.
How can I modify this code to be sure that the input parameter excludedCategories supports remove?
In the general case, you can't. Given an arbitrary class that implements the List API, you cannot tell (statically or dynamically) if the optional methods are supported.
You can use instanceof tests to check if the class of the list is known to implement the method or to not implement it. For example ArrayList and LinkedList do, but Collections.UnmodifiableList does not. The problem is that your code could encounter list classes that your tests don't cover. (Especially if it is a library that is intended to be reusable in other peoples applications.)
You could also try to test the behavior of previously unknown classes; e.g. create a test instance, try a remove to see what happens, and record the behavior in a Map<Class, Boolean>. There are two problems with this:
You may not be able to (correctly) instantiate the list class to test it.
The behavior could depend on how you instantiate the class (e.g. constructor parameters) or even on the nature of the element you are trying to remove ... though the latter is pushing the boundary of plausibility.
In fact, the only completely reliable approach is to call the method and catch the exception (if it is thrown) each and every time.
In short, you can't know. If an object implements an interface (such as List) you can't know if it will actually do what is expected for all of the methods. For instance Collections.unmodifiableList() returns a List that throws UnsupportedOperationException. It can't be filtered out via the method signature if you want to be able to get other List implementations.
The best you can do is to throw IllegalArgumentException for known subtypes that don't support what you want. And catch UnsupportedOperationException for other types of cases. But really you should javadoc your method with what is required and that it throws IllegalArgumentException in other cases.
That depends somewhat on what you're trying to do. In your posted example for example you could just catch the UnsupportedOperationException and do something else instead.
This assumes that you can assume that non-mutable containers will throw that on every attempt to modify the container and will do so without side effects (that is they are indeed non-mutable).
In other cases where your code has other side effects than trying to modify the container you will have to make sure these doesn't happen before knowing that you can modify the container.
You can catch the exception in an utility class like in the example below (as others mentioned). Bad thing is you have to do insert/delete to test if there will be exception. You can not use instanceof since all Collections.Unmodifiablexxx classes have default access.
CollectionUtils:
import java.util.List;
public class CollectionUtils {
public <T> boolean isUnmodifiableList(List<T> listToCheck) {
T object = listToCheck.get(0);
try {
listToCheck.remove(object);
} catch (UnsupportedOperationException unsupportedOperationException) {
return true;
}
listToCheck.add(0, object);
return false;
}
}
Main:
import java.util.Arrays;
import java.util.List;
public class Main {
private static final CollectionUtils COLLECTION_UTILS = new CollectionUtils();
public static void main(String[] args) {
setExcludedCategories(Arrays.asList(1L, 2L, 3L));
}
private static void setExcludedCategories(List<Long> excludedCategories) {
if (excludedCategories.contains(1L)) {
if(!COLLECTION_UTILS.<Long>isUnmodifiableList(excludedCategories)){
excludedCategories.remove(1L);
}
}
}
}
Arrays.asList(T... a) returns the List<java.util.Arrays.ArrayList<E>> which is an immutable list. To get your code working just wrap the result with java.util.ArrayList<T> like shown below
setExcludedCategories(new ArrayList<Long>(Arrays.asList(1L, 2L, 3L)));
Always create new ArrayList from the input list to be sure it's mutable - a lot of useless memory would be used -> NO.
Thats actually the preferred way to do things. "A lot of useless memory" isn't a lot in most practical situations, certainly not in your cited exampled.
And ignoring that, its the only robust and inutitively understood idiom.
The only workable alternative would be to explicitly change the name of your method (thus communicating its behavior better), form the example you show, name it "removeExcludedCategories" if its meant to modify the argument list (but not an objects state).
Otherwise if it is meant as a bulk-setter, you're out of luck, there is no commonly recognized naming idiom that clearly communicates that the argument collection is directly incorporated into the state of an object (its dangerous also because the objects state can then be altered without the object knowing about it).
Also, only marginally related, I would design not an exclusion list, but an exclusion set. Sets are conceptually better suited (no duplicates) and there are set implementations that have far better runtime complexity for the most commonly asked question: contains().
I have been having a lot of trouble with the Concurrent Modification Exception error. With the help of the community I managed to fix my last error, however I think this error is more puzzling.
I am now getting a concurrent modification error while painting, I am worried that this error occurs in the paint function itself. Unlike my last error I am nto removing an entity, in that case I completely understood what was going on just not how to fix it, this error on the other hand I do not understand.
TowerItr = activeTowers.iterator();
while (TowerItr.hasNext()) {
try {
theTower = (ArcherTower) TowerItr.next();
g.drawImage(tower, theTower.y * Map.blockSize, theTower.x * Map.blockSize, this);
} catch (ConcurrentModificationException e) {
}
}
The line that throws the exception is this one:
theTower = (ArcherTower) TowerItr.next();
There are always two sides to a ConcurrentModificationException (CME), and only one side reports the error.
In this case, your code looks perfectly fine. You are looping through the members of the activeTowers.
The stack trace will show you nothing that you don't already know.... you have a CME.
What you need to find out is where you are adding/removing data from the activeTowers collection.
In many cases, there are reasonably easy fixes. A probable fix is to synchronize the access to the activeTowers array in every place it is used. This may be quite hard to do.
Another option is to use a collection from the java.util.concurrent.* package, and to use the toArray(...) methods to get a snapshot of the collection, and then you can iterate that snapshot in your while loop.
// activeTower must be something from java.util.concurrent.*
for (ArcherTower theTower : activeTower.toArray(new ArcherTower[0]) {
g.drawImage(tower, theTower.y * Map.blockSize, theTower.x * Map.blockSize, this);
}
I should add that if you use a java.util.concurrent.* collection, then the iterator() will return a 'stable' iterator too (will not throw CME, and may (or may not) reflect changes in the collection)
Bottom line is that a CME only tells you half the story.... and only your code will tell you the rest....
Carrying on from what our esteemed members have suggested:
1) This error is generally seen when the List is being modified after an Iterator has been extracted.
2) I am looking at your code and it seems alright except this being used in the drawImage() method. This may potentially be altering your List because This has direct access to class members / class variables.
3) This can also happen if multiple threads are accessing the List concurrently. And one of the threads may be trying to alter your List from some other method which share the same instance of the List. I am saying some other method because concurrent read access should not create trouble if multiple threads were accessing this method.
Note: Please all posible code and Stake trace to debug exact problem.
I'm having problems removing an element from the queue. through extensive debugging I found that all the elements are being added, but when I try to remove one, it gives me the same element over and over. here is the code:
private synchronized String accessMyQueue(char[] myInput) {
String myOutput="";
myOutput=convertToString(myQueue.remove());
System.out.println("accessqueue removing:" + myOutput);
}
//and so you can see what's going on in convertToString...
private String convertToString(char[] a) {
String myString = new String(a);
return myString.trim();
}
If myQueue is an instance of a standard Java class implementing the Queue interface, the chance that you have found a bug with it are ... well, close enough to zero that we can discount it as a possibility.
If, on the other hand, you've implemented your own queue then, yes, there may well be a problem but, since psychic debugging is not yet a well-established field of endeavour, you're going to have to show us the code for it :-)
I see one of two possibilities. The first is that you are somehow setting each node of your queue to the same value and you may well be removing items okay (you can detect this by adding one item then trying to remove two). This is far more likely in a language like C where you may inadvertently reuse the same pointer but it's far less likely in Java with its improved strings.
The second and most likely is that you're not removing the element from the queue when you call remove, rather you're returning the string without adjusting whatever your underlying data structure is (or, alternatively, adjusting it wrongly).
Short of seeing the code, that's about as good as I can do.
After your update that you were indeed using LinkedList, I thought I'd give it a shot with a very simple example xx.java:
import java.util.LinkedList;
import java.util.Queue;
public class xx {
public static void main (String args[]) {
Queue<String> myQueue = new LinkedList<String>();
myQueue.add ("abc");
myQueue.add ("def");
System.out.println (myQueue.size());
System.out.println (myQueue.remove());
System.out.println (myQueue.size());
System.out.println (myQueue.remove());
System.out.println (myQueue.size());
try {
System.out.println (myQueue.remove());
} catch (Exception e) {
e.printStackTrace();
}
}
}
This outputs:
2
abc
1
def
0
java.util.NoSuchElementException
at java.util.LinkedList.remove(LinkedList.java:805)
at java.util.LinkedList.removeFirst(LinkedList.java:151)
at java.util.LinkedList.remove(LinkedList.java:498)
at xx.main(xx.java:14)
as expected.
So, bottom line is, I think we're going to need to see more of your code. It's difficult to conceive that, if there were a bug in LinkedList or the Queue interface, it wouldn't have been found yet by the millions of other users :-)
You also want to try putting the System.out.println (myQueue.size()); line at a few strategic places in your code to see what's happening with the queue. This may give you an indication as to what's going on.
I'm occasionally getting a ConcurrentModificationException when I iterate over a list. A Google search informs me that it's probably because I'm altering that list in another thread while iterating over it and that to make this problem go away I should use java.util.concurrent.CopyOnWriteArrayList....
... except I already am.
Apparently, I'm doing something really stupid somewhere.
Does anybody have any insight into how one might induce CopyOnWriteArrayList to toss a ConcurrentModificationException? If it matters, I'm using Java 5.
Edit: Since the mutators I'm using may matter, I'm modifying this list in two ways:
Adding elements to the front. (list.add(0, newElement);)
Using subList to let older items fall off the back. (list = list.subList(0, MAX_LIST_SIZE);)
Do those raise red flags? If so, why? My understanding was that because these operations make a copy of the thing first, any existing iterators would be pointing at the unmodified original and would thus not care. Do I have a hole in my knowledge?
Edit 2: The precise code that's causing the problem is still a bit murky, but I can at least post the exception I'm seeing:
java.util.ConcurrentModificationException
at java.util.concurrent.CopyOnWriteArrayList$COWSubList.checkForComodification(Unknown Source)
at java.util.concurrent.CopyOnWriteArrayList$COWSubList.iterator(Unknown Source)
at....
... where it points to a for-each loop instantiation in my code.
That COWSubList does seem to imply that my call to subList is the root of my problem; I'd still like to understand why.
Edit 3: *facepalm*
CopyOnWriteArrayList.subList() returns a List, not a CopyOnWriteArrayList. The list it returns is under no implied obligation to provide any of COWAL's protections. Which makes using subList() like this to remove elements a Very Bad Idea.
Don't know for certain if this is my culprit, but it's damned suspicious and needs to be corrected regardless.
CopyOnWriteArrayList.subLists throw ConcurrentModificationExceptions if the containing list changes out from underneath it:
public class ListTest {
private static List<int[]> intList;
public static void main (String[] args) {
CopyOnWriteArrayList<Integer> cowal = new CopyOnWriteArrayList<Integer>();
cowal.add(1);
cowal.add(2);
cowal.add(3);
List<Integer> sub = cowal.subList(1, 2);
cowal.add(4);
sub.get(0); //throws ConcurrentModificationException
}
}
Sbodd has the correct answer, but it sounds like using CopyOnWriteArrayList instead of ArrayList is just an attempt to mask the error. The true problem is an attempt to modify the underlying list while iterating over it. You need to find where in your code you are accessing it as such and remove that usage or work around it.