摘要:注意,迭代器的快速失敗行為無法得到保證,因為一般來說,不可能對是否出現(xiàn)不同步并發(fā)修改做出任何硬性保證。快速失敗迭代器會盡最大努力拋出。
fail-fast與fail-safe
在Collection集合的各個類中,有線程安全和線程不安全這2大類的版本。
對于線程不安全的類,并發(fā)情況下可能會出現(xiàn)fail-fast情況;而線程安全的類,可能出現(xiàn)fail-safe的情況。
一、并發(fā)修改當一個或多個線程正在遍歷一個集合Collection的時候(Iterator遍歷),而此時另一個線程修改了這個集合的內(nèi)容(如添加,刪除或者修改)。這就是并發(fā)修改的情況。
二、fail-fast快速失敗fail-fast機制:當遍歷一個集合對象時,如果集合對象的結(jié)構(gòu)被修改了,就會拋出ConcurrentModificationExcetion異常。
有2種情況會拋出該異常:
在單線程的情況下,如果使用Iterator對象遍歷集合對象的過程中,修改了集合對象的結(jié)構(gòu)。如下:
// 1.iterator迭代,拋出ConcurrentModificationException異常 Iteratoriterator = list.iterator(); while (iterator.hasNext()) { String s = iterator.next(); System.out.println(s); // 修改集合結(jié)構(gòu) if ("s2".equals(s)) { list.remove(s); } } // 2.foreach迭代,拋出ConcurrentModificationException異常 for (String s : list) { System.out.println(s); // 修改集合結(jié)構(gòu) if ("s2".equals(s)) { list.remove(s); } }
要想避免拋出異常,應該使用Iterator對象的remove()方法。
// 3.iterator迭代,使用iterator.remove()移除元素不會拋出異常 Iteratoriterator2 = list.iterator(); while (iterator2.hasNext()) { String s = iterator2.next(); System.out.println(s); // 修改集合結(jié)構(gòu) if ("s2".equals(s)) { iterator2.remove(); } }
在多線程環(huán)境下,如果對集合對象進行并發(fā)修改,那么就會拋出ConcurrentModificationException異常。
注意,迭代器的快速失敗行為無法得到保證,因為一般來說,不可能對是否出現(xiàn)不同步并發(fā)修改做出任何硬性保證。快速失敗迭代器會盡最大努力拋出 ConcurrentModificationException。因此,為提高這類迭代器的正確性而編寫一個依賴于此異常的程序是錯誤的做法,迭代器的快速失敗行為應該僅用于檢測 bug。
以ArrayList為例,講解一下fail-fast的機制 1、單線程下,使用iterator迭代時的情況ArrayList繼承自AbstractList類,AbstractList內(nèi)部有一個字段modCount,代表修改的次數(shù)。
ArrayList類的add、remove操作都會使得modCount自增。
當使用ArrayList.iterator()返回一個迭代器對象時。迭代器對象有一個屬性expectedModCount,它被賦值為該方法調(diào)用時modCount的值。這意味著,這個值是modCount在這個時間點的快照值,expectedModCount值在iterator對象內(nèi)部不會再發(fā)送變化!
這時候我們就能明白了,在得到迭代器之后,如果我們使用ArrayList的add、remove等方法,會使得modCount的值自增(發(fā)生了變化),而iterator內(nèi)部的expectedModCount值卻還是之前的快照值。我們再來看iterator的方法實現(xiàn):可以看到,在調(diào)用next方法時,第一步就是檢查modCount值和迭代器內(nèi)部的expectedModCount值是否相等!顯然,這是不等的,所以在調(diào)用next方法的時候,就拋出了ConcurrentModificationException異常。
為什么說迭代器的fail-fast機制是盡最大努力地拋出ConcurrentModificationException異常呢?
原因就是上面我們看到的,只有在迭代過程中修改了元素的結(jié)構(gòu),當再調(diào)用next()方法時才會拋出該異常。也就是說,如果迭代過程中發(fā)生了修改,但之后沒有調(diào)用next()迭代,該異常就不會拋出了!(該異常的機制是告訴你,當前迭代器要進行操作是有問題的,因為集合對象現(xiàn)在的狀態(tài)發(fā)生了改變!)
那為什么iterator.remove()方法可行呢?
下圖中,可以看到,remove方法沒有進行modCount值的檢查,并且手動把expectedModCount值修改成了modCount值,這又保證了下一次迭代的正確。
2、多線程下的情況當然,如果多線程下使用迭代器也會拋出ConcurrentModificationException異常。而如果不進行迭代遍歷,而是并發(fā)修改集合類,則可能會出現(xiàn)其他的異常如數(shù)組越界異常。
三、fail-safe安全失敗Fail-Safe 迭代的出現(xiàn),是為了解決fail-fast拋出異常處理不方便的情況。fail-safe是針對線程安全的集合類。
上面的fail-fast發(fā)生時,程序會拋出異常,而fail-safe是一個概念,并發(fā)容器的并發(fā)修改不會拋出異常,這和其實現(xiàn)有關。并發(fā)容器的iterate方法返回的iterator對象,內(nèi)部都是保存了該集合對象的一個快照副本,并且沒有modCount等數(shù)值做檢查。如下圖,這也造成了并發(fā)容器的iterator讀取的數(shù)據(jù)是某個時間點的快照版本。你可以并發(fā)讀取,不會拋出異常,但是不保證你遍歷讀取的值和當前集合對象的狀態(tài)是一致的!這就是安全失敗的含義。
所以Fail-Safe 迭代的缺點是:首先是iterator不能保證返回集合更新后的數(shù)據(jù),因為其工作在集合克隆上,而非集合本身。其次,創(chuàng)建集合拷貝需要相應的開銷,包括時間和內(nèi)存。
在java.util.concurrent 包中集合的迭代器,如 ConcurrentHashMap, CopyOnWriteArrayList等默認為都是Fail-Safe。
// 1.foreach迭代,fail-safe,不會拋出異常 for (String s : list) { System.out.println(s); if ("s1".equals(s)) { list.remove(s); } } // 2.iterator迭代,fail-safe,不會拋出異常 Iteratoriterator = list.iterator(); while (iterator.hasNext()) { String s = iterator.next(); System.out.println(s); if ("s1".equals(s)) { list.remove(s); } }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/71683.html
摘要:一什么是機制在用迭代器遍歷集合時當集合的結(jié)構(gòu)被修改會拋出異常二什么情況下集合的結(jié)構(gòu)會被修改單線程環(huán)境集合在遍歷的過程中如果要對集合進行增刪操作沒有調(diào)用迭代器的方法而是用的集合自身的方法則可能會產(chǎn)生事件多線程環(huán)境下當一個線程在遍歷某個集合 一.什么是fail-fast機制? 在用迭代器遍歷集合時,當集合的結(jié)構(gòu)被修改,會拋出ConcurrentModificationException異常...
摘要:我們都接觸這些集合類,這些在包的集合類就都是快速失敗的而包下的類都是安全失敗,比如。安全失敗明白了什么是快速失敗之后,安全失敗也是非常好理解的。最后說明一下,快速失敗和安全失敗是對迭代器而言的。 什么是快速失敗(fail-fast)和安全失敗(fail-safe)?它們又和什么內(nèi)容有關系。以上兩點就是這篇文章的內(nèi)容,廢話不多話,正文請慢用。 我們都接觸 HashMap、ArrayLis...
摘要:與在迭代器中的設計在中,最典型的與就是關于迭代器的設計。缺點是,迭代器不能正確及時的反應集合中的內(nèi)容,而且一定程度上也增加了內(nèi)存的消耗。 fail-fast與fail-safe簡介 如果一個系統(tǒng),當有異常或者錯誤發(fā)生時就立即中斷執(zhí)行,這種設計稱之為fail-fast。相反如果我們的系統(tǒng)可以在某種異常或者錯誤發(fā)生時繼續(xù)執(zhí)行,不會被中斷,這種設計稱之為fail-safe。 fail-fas...
摘要:體現(xiàn)的就是適配器模式。數(shù)組對象集合世界中的機制機制集合世界中比較常見的錯誤檢測機制,防止在對集合進行遍歷過程當中,出現(xiàn)意料之外的修改,會通過異常暴力的反應出來。而在增強循環(huán)中,集合遍歷是通過進行的。 前言 學習情況記錄 時間:week 2 SMART子目標 :Java 容器 記錄在學習Java容器 知識點中,關于List的重點知識點。 知識點概覽: 容器中的設計模式 從Array...
閱讀 3794·2021-09-23 11:32
閱讀 2461·2021-09-06 15:01
閱讀 1623·2021-08-18 10:24
閱讀 3458·2019-12-27 11:44
閱讀 3609·2019-08-30 15:52
閱讀 2518·2019-08-30 11:11
閱讀 686·2019-08-29 17:27
閱讀 605·2019-08-29 16:22