快速失败(fail-fast)和安全失败(fail-safe)
我們都接觸 HashMap、ArrayList 這些集合類,這些在 java.util 包的集合類就都是快速失敗的;而 java.util.concurrent 包下的類都是安全失敗,比如:ConcurrentHashMap。
1. 快速失敗(fail-fast)
在使用迭代器對(duì)集合對(duì)象進(jìn)行遍歷的時(shí)候,如果 A 線程正在對(duì)集合進(jìn)行遍歷,此時(shí) B 線程對(duì)集合進(jìn)行修改(增加、刪除、修改),或者 A 線程在遍歷過(guò)程中對(duì)集合進(jìn)行修改,都會(huì)導(dǎo)致 A 線程拋出 ConcurrentModificationException 異常。
具體效果我們看下代碼:
為什么在用迭代器遍歷時(shí),修改集合就會(huì)拋異常時(shí)?
原因是迭代器在遍歷時(shí)直接訪問(wèn)集合中的內(nèi)容,并且在遍歷過(guò)程中使用一個(gè) modCount 變量。集合在被遍歷期間如果內(nèi)容發(fā)生變化,就會(huì)改變 modCount 的值。每當(dāng)?shù)魇褂?hashNext()/next() 遍歷下一個(gè)元素之前,都會(huì)檢測(cè) modCount 變量是否為 expectedModCount 值,是的話就返回遍歷;否則拋出異常,終止遍歷。
2. 安全失敗(fail-safe)
明白了什么是快速失敗之后,安全失敗也是非常好理解的。
采用安全失敗機(jī)制的集合容器,在遍歷時(shí)不是直接在集合內(nèi)容上訪問(wèn)的,而是先復(fù)制原有集合內(nèi)容,在拷貝的集合上進(jìn)行遍歷。 由于迭代時(shí)是對(duì)原集合的拷貝進(jìn)行遍歷,所以在遍歷過(guò)程中對(duì)原集合所作的修改并不能被迭代器檢測(cè)到,故不會(huì)拋 ConcurrentModificationException 異常
我們上代碼看下是不是這樣
最后說(shuō)明一下,快速失敗和安全失敗是對(duì)迭代器而言的。并發(fā)環(huán)境下建議使用 java.util.concurrent 包下的容器類,除非沒(méi)有修改操作。
文章轉(zhuǎn)自:https://juejin.im/post/5be62527f265da617369cdc8
總結(jié)
以上是生活随笔為你收集整理的快速失败(fail-fast)和安全失败(fail-safe)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Spring IOC 核心流程浓缩
- 下一篇: 多图长文 | 聊聊C端转型B端产品那些事