Java 集合中常见 checkForComodification() 方法的作用?

Java 集合中常见 checkForComodification() 方法的到底有什么作用?还有 modCount 和 expectedModCount 作用?

主要是用来实现 fail-fast 机制

有两个线程(线程 A,线程 B),其中线程 A 负责遍历 list、线程 B 修改 list。 -线程 A 在遍历 list 过程的某个时候(此时 expectedModCount = modCount=N),线程启动,
同时线程 B 增加一个元素,这是 modCount 的值发生改变(modCount + 1 = N + 1)。 线程 A 继续遍历执行 next 方法时,
通告 checkForComodification 方法发现 expectedModCount = N , 而 modCount = N + 1,两者不等,
这时就抛出 ConcurrentModificationException 异常,从而产生 fail-fast 机制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* 当前取的是 JDK1.8 ArrayList中的代码
*/

/**
* The number of times this list has been <i>structurally modified</i>.
* Structural modifications are those that change the size of the
* list, or otherwise perturb it in such a fashion that iterations in
* progress may yield incorrect results.
*
* <p>This field is used by the iterator and list iterator implementation
* returned by the {@code iterator} and {@code listIterator} methods.
* If the value of this field changes unexpectedly, the iterator (or list
* iterator) will throw a {@code ConcurrentModificationException} in
* response to the {@code next}, {@code remove}, {@code previous},
* {@code set} or {@code add} operations. This provides
* <i>fail-fast</i> behavior, rather than non-deterministic behavior in
* the face of concurrent modification during iteration.
*
* <p><b>Use of this field by subclasses is optional.</b> If a subclass
* wishes to provide fail-fast iterators (and list iterators), then it
* merely has to increment this field in its {@code add(int, E)} and
* {@code remove(int)} methods (and any other methods that it overrides
* that result in structural modifications to the list). A single call to
* {@code add(int, E)} or {@code remove(int)} must add no more than
* one to this field, or the iterators (and list iterators) will throw
* bogus {@code ConcurrentModificationExceptions}. If an implementation
* does not wish to provide fail-fast iterators, this field may be
* ignored.
*/
protected transient int modCount = 0;

在父类 AbstractList 中定义了一个 int 型的属性:modCount

1
protected transient int modCount = 0;

在 ArrayList 的所有涉及结构变化的方法中都增加 modCount 的值,包括:add()、remove()、addAll()、removeRange()及 clear()方法。这些方法每调用一次,modCount 的值就加 1。注:add()及addAll()方法的modCount的值是在其中调用的ensureCapacity()方法中增加的。
AbstractList 中的 iterator()方法(ArrayList 直接继承了这个方法)使用了一个私有内部成员类 Itr,生成一个 Itr 对象(Iterator 接口)返回:

1
public Iterator iterator() { return new Itr(); }

Itr 实现了 Iterator()接口,其中也定义了一个 int 型的属性:expectedModCount,这个属性在 Itr 类初始化时被赋予 ArrayList 对象的 modCount 属性的值。

1
int expectedModCount = modCount;

注:内部成员类Itr也是ArrayList类的一个成员,它可以访问所有的AbstractList的属性和方法。理解了这一点,Itr类的实现就容易理解了。

在 Itr.hasNext()方法中:

1
public boolean hasNext() { return cursor != size; }

调用了 AbstractList 的 size,比较当前光标位置是否越界。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public Object next()
{
 try
 {
  Object next = get(cursor);
  checkForComodification();
  lastRet = cursor++;
  return next;
 }
 catch(IndexOutOfBoundsException e)
 {
  checkForComodification();
  throw new NoSuchElementException();
 }
}
/**
* 在对一个集合对象进行跌代操作的同时,并不限制对集合对象的元素进行操作
* 这些操作包括一些可能引起跌代错误的add()或remove()等危险操作。
* 在AbstractList中,使用了一个简单的机制来规避这些风险。
* 这就是modCount和expectedModCount的作用所在
*/
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}

Powered by Hexo

Copyright © 2016 - 2019 When I think of you, I smile. All Rights Reserved.

UV : | PV :