java中arraylist的sort方法的 ConcurrentModificationException 问题
最近写代码的时候碰到个问题,
比如我们有一个对象列表,对象中有个排序字段,比如时间或者索性就有个序号1
2
3
4
5
6
7
8
9
10
11
12public class Demo {
private int order = 0;
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}
比如这样,有一个前提,就是这个列表其实是有序的,只是为了防止万一
所以对这个列表进行了排序,就直接使用了ArrayList自带的sort方法,由于是不小心用在了多线程环境
就有出现了一个并发变更报错
也就是这个异常 java.util.ConcurrentModificationException#ConcurrentModificationException()
看下注释1
2This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.
一般情况就是并发环境下进行了变更,
只是这里比较特殊,这个列表没有进行增删,同时是有序的,理论上应该是不会出现变更才对
但是它的确出现了,就得看下这个产生的原因
主要还是来看下这个java.util.ArrayList#sort
的实现跟这个异常的抛出原理1
2
3
4
5
6
7public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
modCount++;
}
可以看到在排序前会有个 modCount
的赋值,如果在进行排序后,这个初始的 modCount
跟当前的不等的话就会抛出这个异常
那么什么时候会出现这两者不相等呢
简单推演下这个并发排序下的情况,线程1和线程2同时进入这个方法,拿到了一样的 modCount
, 然后进行排序,第一个线程比较快,sort玩之后发现两者相等
就到了 modCount++
, 这时候第二个线程刚排序完,发现 modCount
已经比 expectedModCount
大了
这个时候就出现了这个异常的抛出时机
如果这么理解这个异常的确是应该会出现
而不是我们理解的,如果不变更元素,不调整顺序,就不会触发这个并发变更的异常
还是有很多值得学习的点