什么是fail-fast
它是Java集合的一種錯(cuò)誤檢測(cè)機(jī)制。當(dāng)多個(gè)線程對(duì)集合進(jìn)行結(jié)構(gòu)上的改變的操作時(shí),有可能會(huì)產(chǎn)生fail-fast機(jī)制续膳。記住是有可能,而不是一定收班。例如:假設(shè)存在兩個(gè)線程(線程1坟岔、線程2),線程1通過(guò)Iterator在遍歷集合A中的元素闺阱,在某個(gè)時(shí)候線程2修改了集合A的結(jié)構(gòu)(是結(jié)構(gòu)上面的修改炮车,而不是簡(jiǎn)單的修改集合元素的內(nèi)容),那么這個(gè)時(shí)候程序就會(huì)拋出 ConcurrentModificationException 異常,從而產(chǎn)生fail-fast機(jī)制瘦穆。
fail-fast 產(chǎn)生原因
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private class Itr implements Iterator<E> {
int cursor;
int lastRet = -1;
int expectedModCount = ArrayList.this.modCount;
public boolean hasNext() {
return (this.cursor != ArrayList.this.size);
}
public E next() {
checkForComodification();
/** 省略此處代碼 */
}
public void remove() {
if (this.lastRet < 0)
throw new IllegalStateException();
checkForComodification();
/** 省略此處代碼 */
}
final void checkForComodification() {
if (ArrayList.this.modCount == this.expectedModCount)
return;
throw new ConcurrentModificationException();
}
}
從源碼中可以看到每當(dāng)list中的結(jié)構(gòu)發(fā)生變化時(shí)纪隙,modCount參數(shù)就會(huì)發(fā)生變化。而在ArrayList的內(nèi)部類中Iterator扛或、subList中訪問(wèn)元素前都會(huì)去檢查modCount 是否等于從list中繼承過(guò)來(lái)的modCount绵咱,如果不等于,則會(huì)拋出ConcurrentModificationException() 異常熙兔。
fail-fast 解決辦法
- 對(duì)每個(gè)含有modCount的方法進(jìn)行同步處理悲伶,就不會(huì)發(fā)生線程間的fail-fast,但會(huì)造成堵塞住涉。如果錯(cuò)誤的調(diào)用麸锉,依舊會(huì)觸發(fā)fail-fast。
- 使用CopyOnWriteList代替ArrayList.