modCount:Java集合实现快速失败机制的计数器

快速失败机制,是Java集合框架中的一种错误检测机制。多线程下遍历一个非线程安全的集合对象时,如果一个线程在遍历过程中,另一个线程对集合对象的内容进行了修改(增加、删除),则会抛出ConcurrentModificationException。快速失败机制并不保证在非同步下的修改一定会抛出异常,这种机制一般仅用于检测bug。
以ArrayList中的forEach方法为例,看看modCount的作用:
modCount定义于ArrayList的父类AbstractList中

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
	...
	protected transient int modCount = 0;
}

以遍历list为例,modCount是如何实现非线程安全集合的快速失败了?请看forEach的实现

public void forEach(Consumer<? super E> action) {
	// 非空校验
	Objects.requireNonNull(action);
	// 将集合的当前的modCount赋给期待值
	final int expectedModCount = modCount;
	@SuppressWarnings("unchecked")
	final E[] elementData = (E[]) this.elementData;
	final int size = this.size;
	// 开始遍历,并每次校验当前modCount是否等于初始遍历前的预期值
	for (int i=0; modCount == expectedModCount && i < size; i++) {
		action.accept(elementData[i]);
	}
	if (modCount != expectedModCount) {
		throw new ConcurrentModificationException();
	}
}

那么modCount什么时候会改变了?

其实任何试图修改list的地方,它都会改变。如add方法,又如remove方法等

public boolean add(E e) {
	// 这个方法会让modCount自增
	ensureCapacityInternal(size + 1);  // Increments modCount!!
	elementData[size++] = e;
	return true;
}

因此:

  • 集合内部维护一个变量modCount,用来记录集合被修改的次数,诸如add,remove等方法都会使该字段递增;
  • forEach或者迭代器内部也会维护着当前集合的修改次数的字段,它的初始值为集合的modCount值;
  • 当每一次迭代时,迭代器会比较迭代器维护的expectedModCount和modCount的值是否相等,如果不相等就抛ConcurrentModifiedException异常;
  • 如果用迭代器调用remove方法,那么集合和迭代器维护的修改次数都会递增,以保持两个状态的一致;(所以遍历的同时向删除元素,更应该使用迭代器)
  • modCount只是一个普通的int变量,多线程时它的修改(modCount++)并不是原子性,并不能绝对的保证安全性
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值