日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

fail-fast(快速失败/报错机制)-ConcurrentModificationException

發(fā)布時(shí)間:2025/4/16 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 fail-fast(快速失败/报错机制)-ConcurrentModificationException 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>

一、fail-fast機(jī)制(快速報(bào)錯(cuò)機(jī)制)

這是《Java編程思想》中關(guān)于快速報(bào)錯(cuò)機(jī)制的描述

Java容器有一種保護(hù)機(jī)制,能夠防止多個(gè)進(jìn)程同時(shí)修改同一個(gè)容器的內(nèi)容。如果在你迭代遍歷容器的過程中,另一個(gè)進(jìn)程介入其中,并且插入、刪除或者修改此容器內(nèi)的某個(gè)對象,那么就會(huì)出現(xiàn)問題:也許迭代過程中已經(jīng)處理過容器中的該元素了,也許還沒處理,也許在調(diào)用size()之后容器的尺寸收縮了——還有許多災(zāi)難情景。Java容器類類庫采用快速報(bào)錯(cuò)(fail-fast)機(jī)制。它會(huì)探查容器上的任何除了你的進(jìn)程所進(jìn)行的操作以外的所有變化,一旦它發(fā)現(xiàn)其它進(jìn)程修改了容器,就會(huì)立刻拋出ConcurrentModificationException異常。這就是“快速報(bào)錯(cuò)”的意思——即,不是使用復(fù)雜的算法在事后來檢查問題。——from《Java編程思想》p517

下面以一個(gè)demo開始,來理解快速報(bào)錯(cuò)機(jī)制。

二、遍歷容器的幾種方式

程序功能:分別使用for,foreach,iterator來遍歷(迭代)容器,然后刪除其中的值為”傻強(qiáng)”這個(gè)元素。

public class TestTest {private List<String> list;/** * 初始化操作 */@Beforepublic void setUp(){list = new ArrayList<String>();list.add("劉德華"); list.add("周潤發(fā)");list.add("傻強(qiáng)");list.add("古天樂");list.add("劉青云");System.out.println(list);}/** * Demo1:使用for循環(huán)刪除元素 */@Testpublic void testFor(){ for(int i=0;i<list.size();i++){//刪除傻強(qiáng)if("傻強(qiáng)".equals(list.get(i))){list.remove(i);}}System.out.println(list);}/** * Demo2:使用foreach刪除元素【錯(cuò)誤】 */@Testpublic void testForeach(){ for (String s : list) {//刪除傻強(qiáng)if("傻強(qiáng)".equals(s)){list.remove(s);}}System.out.println(list);}/** * Demo3:使用Iterator和Iterator的remove()刪除元素 */@Testpublic void testIterator(){Iterator<String> iterator = list.iterator();while(iterator.hasNext()){String s= iterator.next();//刪除lisiif("傻強(qiáng)".equals(s)){iterator.remove();//使用迭代器的remove()}}System.out.println(list);}/** * Demo4:使用Iterator和集合的remove刪除元素【錯(cuò)誤】 */@Testpublic void testIterator2(){Iterator<String> iterator = list.iterator();while(iterator.hasNext()){String s= iterator.next();//刪除傻強(qiáng)if("傻強(qiáng)".equals(s)){list.remove(s);//使用集合的remove}}System.out.println(list);}/** * Demo5:獲得iterator后進(jìn)行了錯(cuò)誤操作【錯(cuò)誤】 */@Testpublic void testIterator3(){Iterator<String> iterator = list.iterator();//錯(cuò)誤操作list.add("這是錯(cuò)誤的行為");while(iterator.hasNext()){String s= iterator.next();//刪除傻強(qiáng)if("傻強(qiáng)".equals(s)){iterator.remove();}}System.out.println(list);} }

結(jié)果:只有Demo1和Demo3正確。其它demo都會(huì)報(bào)ConcurrentModificationException異常。這里就用到了fail-fast機(jī)制。

三、ArrayList中Iterator源碼分析

接下來開始分析。我們先看看ArrayLis中的關(guān)于迭代器的代碼

public Iterator<E> iterator() {return new Itr();}/** * An optimized version of AbstractList.Itr * * 覆蓋了父類中AbstractList.Itr的實(shí)現(xiàn)(優(yōu)化版) */private class Itr implements Iterator<E> {//下一個(gè)要返回元素的索引int cursor; // index of next element to return//最后一個(gè)要返回元素的索引,-1表示不存在int lastRet = -1; // index of last element returned; -1 if no such//記錄期望的修改次數(shù)(用于保證迭代器在遍歷過程中不會(huì)有對集合的修改操作(迭代器的自身的remove方法除外))int expectedModCount = modCount;public boolean hasNext() {return cursor != size;}@SuppressWarnings("unchecked")public E next() {checkForComodification();int i = cursor;if (i >= size)throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i + 1;return (E) elementData[lastRet = i];}public void remove() {if (lastRet < 0)throw new IllegalStateException();checkForComodification();try {ArrayList.this.remove(lastRet);cursor = lastRet;lastRet = -1;expectedModCount = modCount;} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}/** * 檢查修改次數(shù) */final void checkForComodification() {//實(shí)際的修改次數(shù)和期望的修改次數(shù)不匹配,則拋出并發(fā)修改異常if (modCount != expectedModCount)throw new ConcurrentModificationException();}}

原來,ArrayList從其父類AbstractList繼承了一個(gè)modCount屬性,每當(dāng)對ArrayList進(jìn)行修改(add,remove,clear等)時(shí),就會(huì)相應(yīng)的增加modCount的值。
而ArrayList中迭代器的實(shí)現(xiàn)類Itr也有一個(gè)expectedModCount屬性,一旦使用迭代器遍歷容器時(shí),就要調(diào)用iterator()方法,Itr類也就被初始化,expectedModCount就會(huì)被賦予一個(gè)與modCount相等的值。
接下來在遍歷過程中,每次調(diào)用next()方法獲取值時(shí)都會(huì)檢查modCount和expectedModCount兩個(gè)值是否相等(checkForComodification)。如果在遍歷過程中出現(xiàn)了對集合的其它修改操作,從而造成兩者不等,就會(huì)拋出ConcurrentModificationException。這不就是樂觀鎖的實(shí)現(xiàn)思想嗎。

另外,我們注意到迭代器自身的remove方法并不會(huì)修改modCount的值,這是因?yàn)槲覀兺ǔR矔?huì)通過迭代遍歷去刪除某一個(gè)指定的元素,所以迭代器中自身提供了該remove方法,并保證該remove方法是安全的,而不希望我們在迭代時(shí)使用容器提供remove方法。

四、避免fail-fast

要說明兩點(diǎn)
1.雖然ConcurrentModificationException被譯為并發(fā)修改異常,但這里的”并發(fā)”,并非僅僅指的是多線程場景,前面的例子很顯然是單線程場景。
在單線程情況下

要確保Iterator遍歷過程順利完成,必須保證遍歷過程中不更改集合的內(nèi)容(Iterator的remove()方法除外)。

多線程情況下

如果要在多線程環(huán)境中,在迭代ArrayList的同時(shí)也要修改ArrayList,則可以使用
Collections.synchronizedList(List list)或者CopyOnWriteArrayList。

其中CopyOnWriteArrayList是可以避免ConcurrentModificationException。
實(shí)際上CopyOnWriteArrayList、ConcurrentHashMap和CopyOnWriteArraySet都使用了可以避免ConcurrentModificationException的技術(shù)。

2.迭代器的快速失敗行為無法得到保證,它不能保證一定會(huì)出現(xiàn)該錯(cuò)誤,但是快速失敗操作會(huì)盡最大努力拋出ConcurrentModificationException異常。因此,為提高此類操作的正確性,我們不能依賴于此異常,而要使用上一條中提到的線程安全的容器。

五、CopyOnWriteArrayList不使用fail-fast機(jī)制

通過上面的分析,我么知道了ArrayList一邊使用迭代器遍歷一邊修改是會(huì)發(fā)生ConcurrentModificationException。但是,ArrayList對應(yīng)的線程安全容器CopyOnWriteArrayList卻不會(huì)發(fā)生ConcurrentModificationException。那是為什么呢?先來看源碼。

/** * 返回迭代器 * * 返回的迭代器提供了該迭代器被創(chuàng)建時(shí)列表的快照。 * 當(dāng)移動(dòng)迭代器時(shí),不需要同步。 * 迭代器不支持remove方法 */public Iterator<E> iterator() {return new COWIterator<E>(getArray(), 0);}/** * 內(nèi)部迭代器的實(shí)現(xiàn)類 */private static class COWIterator<E> implements ListIterator<E> {/**數(shù)組的快照*/private final Object[] snapshot;/** Index of element to be returned by subsequent call to next. */private int cursor;/** * 私有的構(gòu)造器 */private COWIterator(Object[] elements, int initialCursor) {cursor = initialCursor;//快照snapshot = elements;}public boolean hasNext() {return cursor < snapshot.length;}public boolean hasPrevious() {return cursor > 0;}@SuppressWarnings("unchecked")public E next() {if (! hasNext())throw new NoSuchElementException();return (E) snapshot[cursor++];}@SuppressWarnings("unchecked")public E previous() {if (! hasPrevious())throw new NoSuchElementException();return (E) snapshot[--cursor];}public int nextIndex() {return cursor;}public int previousIndex() {return cursor-1;}/** * Not supported. Always throws UnsupportedOperationException. * remove is not supported by this iterator. * 不支持。總是拋出不支持的操作異常 * 迭代器不支持remove方法。 */public void remove() {throw new UnsupportedOperationException();}/** * Not supported. Always throws UnsupportedOperationException. * set is not supported by this iterator. * 不支持。總是拋出不支持的操作異常 * 迭代器不支持set方法。 * */public void set(E e) {throw new UnsupportedOperationException();}/** * Not supported. Always throws UnsupportedOperationException. * add is not supported by this iterator. * 不支持。總是拋出不支持的操作異常 * 迭代器不支持aa方法。 * */public void add(E e) {throw new UnsupportedOperationException();}}

原來,CopyOnWriteArrayList中的迭代器在創(chuàng)建之初,會(huì)保存一份對原數(shù)組的快照,之后所有迭代器的操作都是在快照數(shù)組上進(jìn)行的,原數(shù)組一點(diǎn)影響都沒有。同時(shí),即使是對快照數(shù)組進(jìn)行操作,也根本不支持迭代器上的修改(add,set,remove)操作。因此,根本就不會(huì)發(fā)生ConcurrentModificationException。

雖然在迭代時(shí)不支持迭代器上的修改操作,但是仍然可以直接使用容器的修改方法,這點(diǎn)恰好跟ArrayList相反。這也很容易解釋,因?yàn)榈鞑僮鞯氖强煺諗?shù)組,在原容器上進(jìn)行修改也是會(huì)創(chuàng)建一個(gè)新的數(shù)組,因此兩者根本不會(huì)干擾。

public class Demo {public static void main(String[] args) {CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();//添加元素0-4for(int i=0;i<5;i++){list.add(i+"");}System.out.println(list);//[0, 1, 2, 3, 4]//進(jìn)行迭代Iterator iterator = list.iterator();while(iterator.hasNext()){String num = (String) iterator.next();//迭代時(shí),刪除3if("3".equals(num)){//iterator.remove();//iterator不支持修改方法(add,set,remove)list.remove(num);//使用原容器的remove方法};}System.out.println(list);//[0, 1, 2, 4]} }

轉(zhuǎn)載于:https://my.oschina.net/javandroid/blog/878235

《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的fail-fast(快速失败/报错机制)-ConcurrentModificationException的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 在线观看成人动漫 | 动漫毛片 | 成在线人免费视频 | 日本毛片在线 | 欧美xxxxx少妇 | av毛片在线| 亚洲欧美一区二区三区在线 | 国产视频网| 天堂免费在线视频 | 香蕉久久久久久 | 成年人高清视频 | 日本欧美在线视频 | 日韩少妇一区 | 草草屁屁影院 | 91在线观看视频网站 | 亚洲播放 | 一区精品视频 | 日韩一区二区不卡 | 中文字幕一区二区三区电影 | 超碰激情在线 | av网站免费大全 | 九九视频在线 | 国产日本欧美在线观看 | 快灬快灬一下爽69 | 影音先锋成人资源网 | 欧美精品一区二区蜜臀亚洲 | 林雅儿欧洲留学恋爱日记在线 | 狠狠爱综合网 | 大尺度做爰呻吟62集 | 亚洲第一看片 | 无码人妻一区二区三区在线 | 在线观看的免费 | 亚洲日本影院 | 91视频免费在观看 | 欧美精品自拍偷拍 | 国产精品一区二区久久久 | 九草在线视频 | va婷婷 | 国产黄色片免费在线观看 | 欧美特级特黄aaaaaa在线看 | 国产一区不卡 | 丁香婷婷一区二区三区 | 无码国产精品一区二区色情男同 | 99久久久久久久 | 国产人妻精品一区二区三区 | 国产九区 | 亚洲欧洲在线视频 | 超碰一区二区 | 人人妻人人澡人人爽国产一区 | 中文字幕在线观看免费 | 少妇久久久久久被弄到高潮 | 欧美整片第一页 | 九久久 | 精品精品视频 | 夜夜精品一区二区无码 | 97人人爽人人爽人人爽 | 精品无码久久久久 | 久久久天堂国产精品女人 | 免费久久网站 | 欧美性视频一区二区 | 高跟鞋调教—视频|vk | 国产精品美女网站 | 五月天堂网| 久久九九国产精品 | 神马午夜av | 泰坦尼克号3小时49分的观看方法 | 亚洲在线一区二区三区 | 欧美交受高潮1 | 成人在线免费电影 | 欧美日韩不卡合集视频 | 老司机在线观看视频 | 日韩不卡一区二区三区 | 久操久操久操 | 青青草在线免费观看 | 热久久中文| 欧美成人一区二区三区 | 国产小视频自拍 | 国产免费久久精品国产传媒 | 色综合狠狠爱 | 午夜精品视频在线 | 伊人草草 | 成人欧美视频在线观看 | 17c在线观看 | 91精品免费在线 | 一级网站在线观看 | 成年人在线免费 | 99国产精品久久久 | 五十路六十路 | 欧美亚洲韩国 | 国内免费毛片 | 日本欧美一区 | 西西人体高清44rt·net | www精品一区二区三区 | 自拍偷拍福利视频 | 国产伦精品一区二区三区免.费 | 激情黄色小视频 | 亚洲视频你懂的 | aise爱色av| 久久精品aaaaaa毛片 |