modCount:Java集合實現快速失敗機制的計數器

快速失敗機制,是Java集合框架中的一種錯誤檢測機制。多線程下遍歷一個非線程安全的集合對象時,如果一個線程在遍歷過程中,另一個線程對集合對象的內容進行了修改(增加、刪除),則會拋出ConcurrentModificationException。快速失敗機制並不保證在非同步下的修改一定會拋出異常,這種機制一般僅用於檢測bug。

以ArrayList中的forEach方法為例,看看modCount的作用:

modCount定義於ArrayList的父類AbstractList中

<code>public abstract class AbstractList extends AbstractCollection implements List {
\t...
\tprotected transient int modCount = 0;
}
/<code>

以遍歷list為例,modCount是如何實現非線程安全集合的快速失敗了?請看forEach的實現

<code>public void forEach(Consumer super E> action) {
\t// 非空校驗
\tObjects.requireNonNull(action);
\t// 將集合的當前的modCount賦給期待值
\tfinal int expectedModCount = modCount;
\t@SuppressWarnings("unchecked")
\tfinal E[] elementData = (E[]) this.elementData;
\tfinal int size = this.size;
\t// 開始遍歷,並每次校驗當前modCount是否等於初始遍歷前的預期值
\tfor (int i=0; modCount == expectedModCount && i < size; i++) {
\t\taction.accept(elementData[i]);
\t}
\tif (modCount != expectedModCount) {
\t\tthrow new ConcurrentModificationException();
\t}
}/<code>

那麼modCount什麼時候會改變了?

其實任何試圖修改list的地方,它都會改變。如add方法,又如remove方法等

<code>public boolean add(E e) {
\t// 這個方法會讓modCount自增
\tensureCapacityInternal(size + 1); // Increments modCount!!
\telementData[size++] = e;
\treturn true;
}/<code>
  • 集合內部維護一個變量modCount,用來記錄集合被修改的次數,諸如add,remove等方法都會使該字段遞增;
  • forEach或者迭代器內部也會維護著當前集合的修改次數的字段,它的初始值為集合的modCount值;
  • 當每一次迭代時,迭代器會比較迭代器維護的expectedModCount和modCount的值是否相等,如果不相等就拋ConcurrentModifiedException異常;
  • 如果用迭代器調用remove方法,那麼集合和迭代器維護的修改次數都會遞增,以保持兩個狀態的一致;
  • modCount只是一個普通的int變量,多線程時它的修改(modCount++)並不是原子性,並不能絕對的保證安全性


分享到:


相關文章: