范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

failfast的原理解决办法)

  概要
  我们以ArrayList为例,对Iterator的fail-fast机制进行了解。内容包括::
  1 fail-fast简介
  2 fail-fast示例
  3 fail-fast解决办法
  4 fail-fast原理
  5 解决fail-fast的原理 1 fail-fast简介
  fail-fast 机制是java集合(Collection)中的一种错误机制。 当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。
  例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。
  在详细介绍fail-fast机制的原理之前,先通过一个示例来认识fail-fast。 2 fail-fast示例
  示例代码:( FastFailTest.java )  1 import java.util.*;  2 import java.util.concurrent.*;  3   4 /*  5  * @desc java集合中Fast-Fail的测试程序。  6  *  7  *   fast-fail事件产生的条件:当多个线程对Collection进行操作时,若其中某一个线程通过iterator去遍历集合时,该集合的内容被其他线程所改变;则会抛出ConcurrentModificationException异常。  8  *   fast-fail解决办法:通过util.concurrent集合包下的相应类去处理,则不会产生fast-fail事件。  9  * 10  *   本例中,分别测试ArrayList和CopyOnWriteArrayList这两种情况。ArrayList会产生fast-fail事件,而CopyOnWriteArrayList不会产生fast-fail事件。 11  *   (01) 使用ArrayList时,会产生fast-fail事件,抛出ConcurrentModificationException异常;定义如下: 12  *            private static List list = new ArrayList(); 13  *   (02) 使用时CopyOnWriteArrayList,不会产生fast-fail事件;定义如下: 14  *            private static List list = new CopyOnWriteArrayList(); 15  * 16  * @author skywang 17  */ 18 public class FastFailTest { 19  20     private static List list = new ArrayList(); 21     //private static List list = new CopyOnWriteArrayList(); 22     public static void main(String[] args) { 23      24         // 同时启动两个线程对list进行操作! 25         new ThreadOne().start(); 26         new ThreadTwo().start(); 27     } 28  29     private static void printAll() { 30         System.out.println(""); 31  32         String value = null; 33         Iterator iter = list.iterator(); 34         while(iter.hasNext()) { 35             value = (String)iter.next(); 36             System.out.print(value+", "); 37         } 38     } 39  40     /** 41      * 向list中依次添加0,1,2,3,4,5,每添加一个数之后,就通过printAll()遍历整个list 42      */ 43     private static class ThreadOne extends Thread { 44         public 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()遍历整个list 56      */ 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 }
  运行结果 :
  运行该代码,抛出异常java.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机制的集合,建议使用"java.util.concurrent包下的类"去取代"java.util包下的类"。
  所以,本例中只需要将ArrayList替换成java.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.java中实现的。代码如下:  1 package java.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 java.util;   2    3 public class ArrayList extends AbstractList   4         implements List, RandomAccess, Cloneable, java.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<? extends E> 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产生的根本原因"。接下来,我们再进一步谈谈java.util.concurrent包中是如何解决fail-fast事件的。
  还是以和ArrayList对应的CopyOnWriteArrayList进行说明。我们先看看CopyOnWriteArrayList的源码:  1 package java.util.concurrent;  2 import java.util.*;  3 import java.util.concurrent.locks.*;  4 import sun.misc.Unsafe;  5   6 public class CopyOnWriteArrayList  7     implements List, RandomAccess, Cloneable, java.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年Java面试手册。一共整理了1184页PDF文档。私信博主(777)领取,祝大家更上一层楼!!!

突发!乒坛名将退出决赛,伊藤美诚直接夺冠,中国女乒全军覆没北京时间2月12日晚,乒乓球WTT安曼常规赛迎来了女单决赛的较量,然而比赛还没开打多久,中国香港名将杜凯琹就被判定04败北,日本奥运冠军伊藤美诚直接获得了冠军原来杜凯琹突发伤病退赛反制开始!中国亮剑三大王牌,美国始料未及一月,欧盟高官宣称完全同意美国对中国半导体行业的遏制,美日荷进一步达成协议,将会对中国半导体芯片领域采取更大程度的制裁。至此,中国陷入全球半导体高新企业的联手制裁之中。但我国却并没美国芯片在手机芯片市场试图抵御中国芯片,无奈降价也难挽劣势美国芯片在手机芯片市场试图抵御中国芯片,无奈降价也难挽劣势众所周知,美国对于中国的限制已经是越来越大了,现在美国对中国华为更是直接开始下手,而且还把重点放在了芯片领域当中去,想要通论文解读天然海藻酸盐水凝胶珠用于种间和种内双向通讯仅供医学专业人士阅读参考创造一个反映生物系统异质性的微环境对维持生物系统发展至关重要。有利于生物体生长和生存的微环境,应该考虑如质量运输多孔性稳定性弹性大小功能和封闭结构中生物体的10个国外AIAPI让你的项目充满魔力人工智能彻底改变了我们进行软件开发的方式,使用AIAPI比以往任何时候都更容易将尖端技术集成到您的项目中。无论您是希望提高效率自动执行重复性任务,还是增强用户体验,AIAPI都能助CCTV焦点访谈深度聚焦超高清8K王者长虹驰骋新赛道Titer撰稿年后ChapGPT大热彻底燃爆人工智能的热度,科技创新得到史无前例的重视,包括算力超融合等在内的数字经济也受益火爆。然而万变不离其宗,任何概念落地之前,一定会回归到能风华高科肇庆村改项目获省产业园区高质量发展大会表彰2月10日,在广东省产业园区高质量发展大会上,来自肇庆的风华高科祥和工业园高端电容基地作为全省3个村镇工业集聚区升级改造示范项目之一,在大会上受到表彰。风华高科祥和工业园高端电容基老手艺暖了冬季丨红烧羊肉是冬补美味奉贤自有吃羊肉的传统,尤其是大暑,羊肉配烧酒,可谓是大汗淋漓中别有一番滋味,此外还有补益身体的功效。冬天吃羊肉,有滋补作用,只不过一般吃红烧羊肉,在寒冷的冬天,吃上一碗热乎乎的红烧我在神庙前忏悔,向土地说对不起三神与山神,三农与山农,哪个前生注定。天行健,君子以自强不息。地势坤,大地以厚德载物。重要的事说三遍,不管我写了什么,你看到了什么,和我本人没有关系,我当写给自己,你就当我是三农的惊喜地发现0到3岁,小孩子大多是在吃喝拉撒睡玩中度过的,特别是0到1岁,面对于这么大点儿的小孩子,大人觉得吃饱喝足睡够就行了。其实不然,您想想,宝宝在妈妈肚子里还有胎教呢,这个时候的教育更不带着父母游览千佛山,发现旅游的快乐头条创作挑战赛带着父母岳母游览了北京的景点之后,利用周末的时间我和爱人带着三位老人到济南游览。因为是十一黄金周,儿子也赶过来一起游览济南美景。德州紧邻济南,以黄河为界,属于济南城市
早晨空腹喝水很养生?早晨喝水不注意这3点,还不如别喝问题怎么才能每天都收到这种文章呢?答案只需要点击右上角关注即可。空腹喝水只要条件允许还是可以提上日程,在所有的条件当中,有三点需要特别注意,否则还不如暂时别喝水,等到调整到位再喝水48岁接受不了松垂脸,上北京拉皮,7天75天恢复,像变了一个人很多人都会有这样一个感觉,45岁后面部松弛越来越快,照镜子会发现苹果肌的扁平下移及法令纹加深,最重要的还有一点脸方了,下颌缘线条没了,给人臃肿油腻的老态感,这才想起来要做改善,拉皮中国知网反垄断第一案撤诉,网友从头到尾就是一场闹剧而已红星新闻从中国知网反垄断第一案原告郭兵处获悉,杭州市中级人民法院已裁定准许其20日提出的撤诉申请。据红星新闻此前报道,由于知网滥用市场支配地位的行为,向个人用户收取开放学术不端文献中国企业领头羊营收2。97万亿排第一,专利数量超过华为美的8月3日,2022年财富世界500强正式出炉。中国大陆(含香港)公司达到136家,同比增加1家,加上台湾地区企业,共有145家中国公司上榜紧随其后的是美国(124家)。值得一提的是记者最新报道引爆争议,球迷吐槽这样的联赛完全没有存在的意义北京时间8月4日,中国足球传来最新消息,记者孙纬伦曝出争议猛料,武汉长江因为欠薪就快凑不齐首发了,这样的情况对步履维艰的中超联赛来说,显然是个不小的打击。武汉队本赛季迎来重大转变,气血不足百病生,女性尤其要重视!两味药,气色好了睡得香了我们常说女子以气血为根本!气血充足,面色红润有光泽,看起来相对同龄人来说更年轻一些可若是气血不足的话,那么人就会容易显老,皮肤容易长斑点皱纹,整个人看起来也是无精打采的现代生活压力锗的应用及回收简介锗的应用锗是一种金属,可以用于太阳能电池,为外层空间的车辆和系统提供动力。你知道这个金属已经进入火星了吗?是的,锗基板由于其能量转换效率而成为太空太阳能电池的基础。前两个火星探测器白富美李白五洲辣妹,北大博士,为何能让撒贝宁神魂颠倒?当撒贝宁还沉浸在与章子怡的恋情时,她未来的妻子早已来到了中国。彼时撒贝宁还不知道,自己有一天也会掉进图谋已久的陷阱。2013年,撒贝宁和章子怡结束了两个月的恋情后,很长一段时间都处姚明见证!状元郎大爆发,清华大学三连冠,广工3分惜败,北大第5万众瞩目的CUBA(中国大学生篮球联赛)第24届比赛落幕,决赛清华大学89比86击败广东工业大学夺得本届CUBA的冠军,清华大学实现了3连冠王朝,值得一说的是此前有两支球队实现过3第二届点亮海门之美文旅夜市等你来慢品烟火色,闲观岁月长拾花酿酒意,不负好时光浪漫七夕来一场摇滚与美食的浪漫相约8月4日就在明晚江海文化公园第二届点亮海门之美文旅夜市等你来!多种美食等你来品夜市必备多个乐队等你来嗨第五三国杀合集,把这些角色放进斗地主会怎样大家好,之前我给大家做过几期第五人格和三国杀的混合武将,说是集合,其实也就只有三个武将。正好做了三个,我就想把它们放进斗地主里,看看会有什么对局效果。首先还是先介绍一下我们的几个角