fail-fast####
fail-fast机制是java集合中的一种错误机制。当多个线程对统一集合的内容进行操作时,就可能会产生fail-fast事件。
𞀈 当某一个线程通过iterator遍历某个集合时,该集合的线程被其他线程改变了,就会抛出异常,产生fail-fast事件。
fail-fast解决办法####
fail-fast机制是一种错误检测机制,用来检测错误,JDK并不保证fail-fast机制一定会发生。如果在多线程环境下使用fail-fast机制的集合,建议使用java.util.concurrent包下的类。
fail-fast原理####
package java.util;
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
...
// AbstractList中唯一的属性
// 用来记录List修改的次数:每修改一次(添加/删除等操作),将modCount+1
protected transient int modCount = 0;
// 返回List对应迭代器。实际上,是返回Itr对象。
public Iterator<E> iterator() {
return new Itr();
}
// Itr是Iterator(迭代器)的实现类
private class Itr implements Iterator<E> {
int cursor = 0;
int lastRet = -1;
// 修改数的记录值。
// 每次新建Itr()对象时,都会保存新建该对象时对应的modCount;
// 以后每次遍历List中的元素的时候,都会比较expectedModCount和modCount是否相等;
// 若不相等,则抛出ConcurrentModificationException异常,产生fail-fast事件。
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
// 获取下一个元素之前,都会判断“新建Itr对象时保存的modCount”和“当前的modCount”是否相等;
// 若不相等,则抛出ConcurrentModificationException异常,产生fail-fast事件。
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
...
}
在调用next()和remove()时,都会执行checkForComodification()。如果modCount不等于expectedModCount,就会抛出异常,产生fail-fast事件。
expectedModCount在创建Itr对象时,被赋值为modCount。而expectedModCount不可能被修改,所以需要知道modCount何时被改变。
查看ArrayList源码,可以得知add()、remove()等设计到修改集合中元素个数的操作,都会改变modCount的值。
解决fail-fast的原理####
以ArrayList对应的CopyOnWriteArrayList为例,通过观察源码可知:
1、ArrayList继承AbstractList,而CopyWriteArrayList没有继承AbstractList,仅仅只是实现了List接口
2、ArrayList的iterator()函数返回的Iterator是在AbstractList中实现的,而CopyOnWriteArrayList是自己实现的Iterator
ArrayList的Iterator实现类中调用next()时,会“调用checkForComodification()比较‘expectedModCount’和‘modCount’的大小”;但是,CopyOnWriteArrayList的Iterator实现类中,没有所谓的checkForComodification(),更不会抛出ConcurrentModificationException异常
CopyOnWriteArrayList对会改变集合元素的操作都使用synchronized关键字进行了同步,保证了线程安全