List,map这些集合结构中常能看到modCount属性,在对集合进行新增或移除操作时会使modCount+1,这是一个记录集合变化次数的变量。作用是在使用迭代器Iterator对集合进行遍历时,用modCount来判断集合内数据没有发生变化,否则会抛出异常。
ArrayList中的Iterator:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
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];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
1、expectedModCount的初值为modCount
2、hasNext的判断条件为cursor!=size,就是当前迭代的位置不是数组的最大容量值就返回true
3、next和remove操作之前都会先调用checkForComodification来检查expectedModCount和modCount是否相等
如果没checkForComodification去检查expectedModCount与modCount相等,这个程序肯定会报越界异常ArrayIndexOutOfBoundsException
因为有modCount的存在,在使用多线程对非线程安全的集合进行操作时,使用迭代器循环会产生modCount != expectedModCount的情况,会抛出异常。
再查看Vector这个线程安全的list,它的内部实现,在新增和移除方法上添加了sychorized关键字,并且内部迭代器的next()方法也进行了线程同步:
public E next() {
synchronized (Vector.this) {
checkForComodification();
int i = cursor;
if (i >= elementCount)
throw new NoSuchElementException();
cursor = i + 1;
return elementData(lastRet = i);
}
}
网友评论