Why is there a ConcurrentModificationException even though the list is in sync?
I have a multithreaded android app.
There is some possibility that two or more triggers can work on the same piece of code.
I have a list of objects.
I made it syncronized with Collections.synchronizedList
private List<WmGroupItemSample> mGroupItemSampleList;
mGroupItemSampleList = new ArrayList<WmGroupItemSample>();
mGroupItemSampleList = Collections.synchronizedList(mGroupItemSampleList);
However, sometimes I get Exception on line:
Collections.sort(mGroupItemSampleList, new GroupItemSampleComparator());
java.util.ConcurrentModificationException
at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:62)
at java.util.Collections.sort(Collections.java:1895)
- Is this thread legal?
- Do I need to create a copy and sort by copy?
- Why
Collections.synchronizedList
doesn't this exception prevent it?
[EDIT]
GroupItemSampleComparator
public class GroupItemSampleComparator implements java.util.Comparator<WmGroupItemSample> {
public GroupItemSampleComparator() {
super();
}
public int compare(WmGroupItemSample s1, WmGroupItemSample s2) {
return ( (s2.getStartDate() - s1.getStartDate()) > 0 ) ? (-1) : (1);
}
}
Thank,
source to share
The main problem is that the synced list is out of sync in a useful way.
The problem is that while its methods are synchronized, actions like moving elements that need to be atomic are not, as the individual calls needed to move are not synchronized together. This means that other threads can communicate between calls to individual methods. As such, synchronized collections are pretty much out of date.
Despite this disadvantage, if you have another stream, add an item while sorting the stream, you will get this exception, because sorting the iteration and changing the list during iteration throws an exception.
Luckily, the JDK has new Collection classes that have industrial strength (and useful) synchronization courtesy of java.util.concurrent
.
Replace your list CopyOnWriteArrayList
, don't sync it and you should be good to go.
source to share
Collections.synchronizedList(list)
returns a synchronized list, which means the list methods will be synchronized (only one of them can run at the same time).
However, this doesn't mean you can't call a list method while someone else (or maybe you) is iterating over the list with their iterator (the iterators returned iterator()
are not synchronized). synchronizedList()
does not protect you from getting ConcurrentModificationException
if someone is iterating over the list and it is modified in any other way than the iterator methods.
Edit:
Also yours is GroupItemSampleComparator
bad, it should return 0
if past 2 objects are considered equal to their method equals()
. Try this (if it getStartDate()
returns long
):
public int compare(WmGroupItemSample s1, WmGroupItemSample s2) {
long diff = s2.getStartDate() - s1.getStartDate();
return diff > 0 ? -1 : diff < 0 ? 1 : 0;
}
source to share
Maybe it helps - not to see all the code and the possibility of other accesses to the list. Quoting from the Javadoc onsynchronizedList(List<T> list)
Returns a synchronized (thread safe) list supported by the specified list. To ensure consistent access, it is imperative that all support list access is done through the returned list.
It is imperative that the user manually synchronize on the returned list while iterating over it:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
So, are all iterations in this list guarded this way?
source to share