前段时间看了ArrayList的源码,里面讲到Iterator迭代器和快速失败,安全失败这块内容,之前没碰到过,学习了一番~ 忘了好多,如今总结一下java
(视频资源:www.bilibili.com/video/BV1gE…)git
Iterator
对象称为迭代器(设计模式的一种),迭代器能够对集合进行遍历,但每个集合内部的数据结构多是不尽相同的,因此每个集合存和取都极可能是不同的,虽然咱们能够人为地在每个类中定义 hasNext()
和 next()
方法,但这样作会让整个集合体系过于臃肿。因而就有了迭代器。设计模式
迭代器是将这样的方法抽取出接口,而后在每一个类的内部,定义本身迭代方式,这样作就规定了整个集合体系的遍历方式都是 hasNext()
和next()
方法,使用者不用管怎么实现的,会用便可。迭代器的定义为:提供一种方法访问一个容器对象中各个元素,而又不须要暴露该对象的内部细节。安全
Iterator
主要是用来遍历集合用的,它的特色是更加安全,由于它能够确保,在当前遍历的集合元素被更改的时候,就会抛出 ConcurrentModificationException
异常。markdown
若是单单使用List集合里的remove方法,会 抛出 ConcurrentModificationException
异常,出现一些问题数据结构
迭代器的默认remove删除方法 it.remove() 直接删除(迭代器自带的remove方法),其实迭代器的remove方法底层仍是用的arraylist的remove方法来删除元素,可是这个方法中删除的时候每次都会给预期修改次数的变量进行赋值,因此怎么都不会产生并发修改异常多线程
快速失败(fail-fast) 是 Java 集合的一种错误检测机制。在使用迭代器对集合进行遍历的时候,咱们在多线程下操做非安全失败(fail-safe)的集合类可能就会触发 fail-fast 机制,致使抛出 ConcurrentModificationException
异常。 另外,在单线程下,若是在遍历过程当中对集合对象的内容进行了修改的话也会触发 fail-fast 机制。并发
注:加强 for 循环也是借助迭代器进行遍历。ide
举个例子:多线程下,若是线程 1 正在对集合进行遍历,此时线程 2 对集合进行修改(增长、删除、修改),或者线程 1 在遍历过程当中对集合进行修改,都会致使线程 1 抛出 ConcurrentModificationException
异常。oop
为何呢?
每当迭代器使用 hashNext()
/next()
遍历下一个元素以前,都会检测 modCount
变量是否为 expectedModCount
值,是的话就返回遍历;不然抛出异常,终止遍历。
若是咱们在集合被遍历期间对其进行修改的话,就会改变 modCount
的值,进而致使 modCount != expectedModCount
,进而抛出 ConcurrentModificationException
异常。
注:经过
Iterator
的方法修改集合的话会修改到expectedModCount
的值,因此不会抛出异常。
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
复制代码
使用 Iterator
提供的 remove
方法,能够修改到 expectedModCount
的值。因此,才不会再抛出ConcurrentModificationException
异常。
明白了快速失败(fail-fast)以后,安全失败(fail-safe)咱们就很好理解了。
采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。因此,在遍历过程当中对原集合所做的修改并不能被迭代器检测到,故不会抛 ConcurrentModificationException
异常。
最后补充一点:迭代器的remove只能解决单线程下的异常抛出问题,多线程的问题仍是得靠使用安全失败机制的集合容器。
最后,这篇文章只是总结了大概,并无把以前看过的视频源码内容所有写进来,必要时能够再看一遍视频,而后看看源码~