您当前的位置:首页 >> 家居资讯

fail-fast总结(通过ArrayList来说明fail-fast的分析方法、解决办法)

2025-05-28 12:27:31

c void run() {45 int i = 0;46 while (i<6) {47 list.add(String.valueOf(i));48 printAll();49 i++;50 }51 }52 }53 54 /**55 * 向list中则会依次附加成10,11,12,13,14,15,每附加成一个近以后,就通过printAll()查找整个list56 */57 private static class ThreadTwo extends Thread {58 public void run() {59 int i = 10;60 while (i<16) {61 list.add(String.valueOf(i));62 printAll();63 i++;64 }65 }66 }67 68 }

开始运行结果:开始运行该标识符,跳出极度ja.util.ConcurrentModificationException!即,造成了fail-fast事件真相!

结果陈述:(01) FastFailTest中则会通过 new ThreadOne().start() 和 new ThreadTwo().start() 同时启动时两个虚拟机去管理系统设计list。 ThreadOne虚拟机:向list中则会依次附加成0,1,2,3,4,5。每附加成一个近以后,就通过printAll()查找整个list。 ThreadTwo虚拟机:向list中则会依次附加成10,11,12,13,14,15。每附加成一个近以后,就通过printAll()查找整个list。(02) 当某一个虚拟机查找list的现实生活中则会,list的细节被另外一个虚拟机所彻底改变了;就则会跳出ConcurrentModificationException极度,造成了fail-fast事件真相。

3 fail-fast应付前提

fail-fast管理系统,是一种错误样品管理系统。它只能被用来样品错误,因为JDK极为保证fail-fast管理系统一定则会发生。若在多虚拟机环境下采用fail-fast管理系统的交集,建议采用“ja.util.concurrent包下的类”去取代“ja.util包下的类”。所以,本例中则会只需要将ArrayList附加成ja.util.concurrent包下对应的类即可。即,将标识符

private static List list = new ArrayList();

附加为

private static List list = new CopyOnWriteArrayList();

则可以应付该前提。

4 fail-fast理论

造成了fail-fast事件真相,是通过跳出ConcurrentModificationException极度来触发的。那么,ArrayList是如何跳出ConcurrentModificationException极度的呢?

我们其实,ConcurrentModificationException是在管理系统设计Iterator时跳出的极度。我们再次看看Iterator的源码。ArrayList的Iterator是在父类AbstractList.ja中则会发挥作用的。标识符如下:

1 package ja.util; 2 3 public abstract class AbstractList extends AbstractCollection implements List { 4 5 ... 6 7 // AbstractList中则会唯一的属性 8 // 用来记录List简化的次近:每简化一次(附加成/撤下等管理系统设计),将modCount+1 9 protected transient int modCount = 0;10 11 // 返回List对应渐进探头。其实,是返回Itr某类。12 public Iterator iterator() {13 return new Itr();14 }15 16 // Itr是Iterator(渐进探头)的发挥作用类17 private class Itr implements Iterator {18 int cursor = 0;19 20 int lastRet = -1;21 22 // 简化近的记录绝对值。23 // 每次另建Itr()某类时,才则会完好另建该某类时对应的modCount;24 // 以后每次查找List中则会的金属元素的时候,才则会来得expectedModCount和modCount应该也就是说;25 // 若不也就是说,则跳出ConcurrentModificationException极度,造成了fail-fast事件真相。26 int expectedModCount = modCount;27 28 public boolean hasNext() {29 return cursor != size();30 }31 32 public E next() {33 // 给予下一个金属元素此前,才则会推论“另建Itr某类时完好的modCount”和“当前的modCount”应该也就是说;34 // 若不也就是说,则跳出ConcurrentModificationException极度,造成了fail-fast事件真相。35 checkForComodification();36 try {37 E next = get(cursor);38 lastRet = cursor++;39 return next;40 } catch (IndexOutOfBoundsException e) {41 checkForComodification();42 throw new NoSuchElementException();43 }44 }45 46 public void remove() {47 if (lastRet == -1)48 throw new IllegalStateException();49 checkForComodification();50 51 try {52 AbstractList.this.remove(lastRet);53 if (lastRet < cursor)54 cursor---;55 lastRet = -1;56 expectedModCount = modCount;57 } catch (IndexOutOfBoundsException e) {58 throw new ConcurrentModificationException();59 }60 }61 62 final void checkForComodification() {63 if (modCount != expectedModCount)64 throw new ConcurrentModificationException();65 }66 }67 68 ...69 }

于是便则会,我们可以见到在加载 next() 和 remove()时,才则会可执行 checkForComodification()。若 “modCount 不等于 expectedModCount”,则跳出ConcurrentModificationException极度,造成了fail-fast事件真相。

要搞说出 fail-fast管理系统,我们就要需要理解什么时候“modCount 不等于 expectedModCount”!从Itr类中则会,我们其实 expectedModCount 在创建人Itr某类时,被赋绝对值为 modCount。通过Itr,我们其实:expectedModCount不可能被简化为不等于 modCount。所以,需要考究的就是modCount何时则会被简化。

最后,我们查看ArrayList的源码,来看看modCount是如何被简化的。

1 package ja.util; 2 3 public class ArrayList extends AbstractList 4 implements List, RandomAccess, Cloneable, ja.io.Serializable 5 { 6 7 ... 8 9 // list中则会容量发生变化时,对应的联动函近 10 public void ensureCapacity(int minCapacity) { 11 modCount++; 12 int oldCapacity = elementData.length; 13 if (minCapacity> oldCapacity) { 14 Object oldData[] = elementData; 15 int newCapacity = (oldCapacity * 3)/2 + 1; 16 if (newCapacity < minCapacity) 17 newCapacity = minCapacity; 18 // minCapacity is usually close to size, so this is a win: 19 elementData = Arrays.copyOf(elementData, newCapacity); 20 } 21 } 22 23 24 // 附加成金属元素到队列最后 25 public boolean add(E e) { 26 // 简化modCount 27 ensureCapacity(size + 1); // Increments modCount!! 28 elementData[size++] = e; 29 return true; 30 } 31 32 33 // 附加成金属元素到指定的位置 34 public void add(int index, E element) { 35 if (index> size || index < 0) 36 throw new IndexOutOfBoundsException( 37 "Index: "+index+", Size: "+size); 38 39 // 简化modCount 40 ensureCapacity(size+1); // Increments modCount!! 41 System.arraycopy(elementData, index, elementData, index + 1, 42 size - index); 43 elementData[index] = element; 44 size++; 45 } 46 47 // 附加成交集 48 public boolean addAll(Collection c) { 49 Object[] a = c.toArray(); 50 int numNew = a.length; 51 // 简化modCount 52 ensureCapacity(size + numNew); // Increments modCount 53 System.arraycopy(a, 0, elementData, size, numNew); 54 size += numNew; 55 return numNew != 0; 56 } 57 58 59 // 撤下指定位置的金属元素 60 public E remove(int index) { 61 RangeCheck(index); 62 63 // 简化modCount 64 modCount++; 65 E oldValue = (E) elementData[index]; 66 67 int numMoved = size - index - 1; 68 if (numMoved> 0) 69 System.arraycopy(elementData, index+1, elementData, index, numMoved); 70 elementData[---size] = null; // Let gc do its work 71 72 return oldValue; 73 } 74 75 76 // 快速撤下指定位置的金属元素 77 private void fastRemove(int index) { 78 79 // 简化modCount 80 modCount++; 81 int numMoved = size - index - 1; 82 if (numMoved> 0) 83 System.arraycopy(elementData, index+1, elementData, index, 84 numMoved); 85 elementData[---size] = null; // Let gc do its work 86 } 87 88 // 清空交集 89 public void clear() { 90 // 简化modCount 91 modCount++; 92 93 // Let gc do its work 94 for (int i = 0; i < size; i++) 95 elementData[i] = null; 96 97 size = 0; 98 } 99 100 ...101 }

于是便则会,我们见到:无论是add()、remove(),还是clear(),只要涉及到简化交集中则会的金属元素个近时,才则会彻底改变modCount的绝对值。

最后,我们再次管理系统的梳理一下fail-fast是怎么造成了的。步骤如下:(01) 另建了一个ArrayList,名称为arrayList。(02) 向arrayList中则会附加成细节。(03) 另建一个“虚拟机a”,并在“虚拟机a”中则会通过Iterator有规律的擦除arrayList的绝对值。(04) 另建一个“虚拟机b”,在“虚拟机b”中则会撤下arrayList中则会的一个“终端A”。(05) 这时,就则会造成了古怪的事件真相了。 在某一预感,“虚拟机a”创建人了arrayList的Iterator。此时“终端A”仍然存在于arrayList中则会,创建人arrayList时,expectedModCount = modCount(假设它们此时的绝对值为N)。 在“虚拟机a”在查找arrayList现实生活中则会的某一预感,“虚拟机b”可执行了,并且“虚拟机b”撤下了arrayList中则会的“终端A”。“虚拟机b”可执行remove()顺利完成撤下管理系统设计时,在remove()中则会可执行了“modCount++”,此时modCount变成了N+1!“虚拟机a”接着查找,当它可执行到next()函近时,加载checkForComodification()来得“expectedModCount”和“modCount”的大小;而“expectedModCount=N”,“modCount=N+1”,这样,便跳出ConcurrentModificationException极度,造成了fail-fast事件真相。

相继,我们就完全认识到了fail-fast是如何造成了的!即,当多个虚拟机对同一个交集顺利完成管理系统设计的时候,某虚拟机访问交集的现实生活中则会,该交集的细节被其他虚拟机所彻底改变(即其它虚拟机通过add、remove、clear等工具,彻底改变了modCount的绝对值);这时,就则会跳出ConcurrentModificationException极度,造成了fail-fast事件真相。

5 应付fail-fast的理论

右边,陈述了“应付fail-fast管理系统的前提”,也其实了“fail-fast造成了的从根本上”。最后,我们从新谈到ja.util.concurrent包中则会是如何应付fail-fast事件真相的。还是以和ArrayList对应的CopyOnWriteArrayList顺利完成陈述。我们再次看看CopyOnWriteArrayList的源码:

1 package ja.util.concurrent; 2 import ja.util.*; 3 import ja.util.concurrent.locks.*; 4 import sun.misc.Unsafe; 5 6 public class CopyOnWriteArrayList 7 implements List, RandomAccess, Cloneable, ja.io.Serializable { 8 9 ...10 11 // 返回交集对应的渐进探头12 public Iterator iterator() {13 return new COWIterator(getArray(), 0);14 }15 16 ...17 18 private static class COWIterator implements ListIterator {19 private final Object[] snapshot;20 21 private int cursor;22 23 private COWIterator(Object[] elements, int initialCursor) {24 cursor = initialCursor;25 // 另建COWIterator时,将交集中则会的金属元素完好到一个新的拷贝近组中则会。26 // 这样,当早期交集的信息彻底改变,拷贝信息中则会的绝对值也才则会发生变化。27 snapshot = elements;28 }29 30 public boolean hasNext() {31 return cursor < snapshot.length;32 }33 34 public boolean hasPrevious() {35 return cursor> 0;36 }37 38 public E next() {39 if (! hasNext())40 throw new NoSuchElementException();41 return (E) snapshot[cursor++];42 }43 44 public E previous() {45 if (! hasPrevious())46 throw new NoSuchElementException();47 return (E) snapshot[---cursor];48 }49 50 public int nextIndex() {51 return cursor;52 }53 54 public int previousIndex() {55 return cursor-1;56 }57 58 public void remove() {59 throw new UnsupportedOperationException();60 }61 62 public void set(E e) {63 throw new UnsupportedOperationException();64 }65 66 public void add(E e) {67 throw new UnsupportedOperationException();68 }69 }70 71 ...72 73 }

于是便则会,我们可以看得出来:

(01) 和ArrayList继承于AbstractList各有不同,CopyOnWriteArrayList没有继承于AbstractList,它仅仅只是发挥作用了List模块。(02) ArrayList的iterator()函近返回的Iterator是在AbstractList中则会发挥作用的;而CopyOnWriteArrayList是自己发挥作用Iterator。(03) ArrayList的Iterator发挥作用类中则会加载next()时,则会“加载checkForComodification()来得‘expectedModCount’和‘modCount’的大小”;但是,CopyOnWriteArrayList的Iterator发挥作用类中则会,没有所谓的checkForComodification(),更才则会跳出ConcurrentModificationException极度!

所有的面试题目都不是一成不变的,特别是像前沿大厂,右边的面试题只是给大家一个独有作用,最主要的是给自己增加知识的储备,有备无患。最后给大家共享Spring新作的研习笔记和面试题,包含spring面试题、spring cloud面试题、spring boot面试题、spring教材笔记、spring boot教材笔记、最新阿里巴巴开发手册(63页PDF总结)、2022年Ja面试手册。一共整理了1184页PDF信息库。私信博客(777)缴,祝大家更上一层楼!!!

小孩没食欲不想吃饭怎么办
小儿健胃消食片
小孩经常便秘是什么原因
科兴制药创新生物药研发制药一体化
太极集团
科兴制药
核医学科
科兴制药
视疲劳滴哪个滴眼液比较好
哪种眼药水可以长期使用缓解视疲劳
友情链接