原文連結:https://mp.weixin.qq.com/s/dPA7zohM2LfBrZT-sfQnyg你真的瞭解 fail-fast和 fail-safe嗎?簡介java.util 包下的 屬於 fail-fast , 快速失敗~ java.util.concurrent
2021-09-06 03:03:41
原文連結:https://mp.weixin.qq.com/s/dPA7zohM2LfBrZT-sfQnyg
java.util 包下的 屬於 fail-fast , 快速失敗~
java.util.concurrent 包下的 屬於 fail-safe ,安全失敗~
簡單來說 就是 fail-fast 在迭代時,如果發現 該集合資料 結構被改變 (modCount != expectedModCount),就會 拋出 ConcurrentModificationException
小夥伴們可以參考下 下面的程式碼簡單實驗一下~
實驗物件是 Hashtable,這裡採用 jdk1.7 的寫法 ~
因為博主還在研究 下文中 ConcurrentHashMap 在7和8中有啥不一樣
class E implements Runnable{ Hashtable<String, String> hashtable; public E(Hashtable<String, String> hashtable) { this.hashtable = hashtable; } private void add(Hashtable<String, String> hashtable){ for (int i = 0; i < 10000000; i++) { hashtable.put("a",""+i); } } @Override public void run() { add(hashtable); }}public class D { public static void main(String[] args) { Hashtable<String, String> hashtable = new Hashtable<String, String>(); hashtable.put("1","2"); hashtable.put("2","2"); hashtable.put("3","2"); hashtable.put("4","2"); hashtable.put("15","2"); new Thread(new E(hashtable)).start(); Set<Map.Entry<String, String>> entries = hashtable.entrySet(); Iterator<Map.Entry<String, String>> iterator = entries.iterator(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } while (iterator.hasNext()){ System.out.println(iterator.next()); iterator.remove(); } }}
效果如圖:
當集合資料結構發生變化時,這兩個值是不相等的,所以會拋出該異常~ 。
雖然 HashTable 是 執行緒安全的 , 但是它有 fail-fast 機制 ,所以在多執行緒情況下進行 迭代 也不能去修改它的資料結構!
fail-fast 機制 不允許併發修改!
class E implements Runnable{ ConcurrentHashMap<String, String> concurrentHashMap; public E(ConcurrentHashMap<String, String> concurrentHashMap) { this.concurrentHashMap = concurrentHashMap; } private void add( ConcurrentHashMap<String, String> concurrentHashMap){ for (int i = 0; i < 100000; i++) { concurrentHashMap.put("a"+i,""+i); } } @Override public void run() { add(concurrentHashMap); }}public class D { public static void main(String[] args) { ConcurrentHashMap<String, String> concurrentHashMap = new ConcurrentHashMap<String, String>(); concurrentHashMap.put("1","2"); concurrentHashMap.put("2","2"); concurrentHashMap.put("3","2"); concurrentHashMap.put("4","2"); concurrentHashMap.put("15","2"); new Thread(new E(concurrentHashMap)).start(); try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } Set<Map.Entry<String, String>> entries = concurrentHashMap.entrySet(); for (Map.Entry<String, String> entry : entries) { System.out.println(entry);// 這裡不用呼叫 iterator 去 remove concurrentHashMap.remove(entry.getKey()); } }}
效果如圖:
程式碼運行講解,執行緒A 往裡加資料,執行緒B 遍歷它的資料,並刪除。
可以看到這裡並沒有報錯~,但是它也不能保證遍歷到所有的值 (可以理解為無法獲取到最新的值)
有沒有感受到一絲絲 安全失敗的感覺~
哈哈哈 它的特點就是 允許併發修改,不會拋出 ConcurrentModificationException ,但是無法保證拿到的是最新的值
不知道小夥伴們看完上面的實驗程式碼有沒有疑惑
(((*)
別急~ 我們先來看看使用這個迭代器中發生了什麼?
源碼走起~
小夥伴們可以看看下面四張圖~
創建迭代器的過程
從 圖一 可以看到會去創造一個 EntryIterator, 而 它又 繼承了 HashIterator ,在初始化時,會先呼叫父類的構造器。
從 圖三 可以發現 HashIterator 在初始化 時,會去呼叫 advance 方法 (這裡就不展開這個 concurrentHashMap結構啦~ ) 這裡的重點在最後一張圖 , 它呼叫的是 UNSAFE.getObjectVolatile 。
它的作用是 強制從主存中獲取屬性值。
小夥伴們可以自行對比下 HashMap 或者 上面的 HashTable,他們都是直接 拿到程式碼中定義的這個 Entry[]~。
不知道小夥伴們 get 得到這個點沒有~
哈哈哈 容我嘮叨嘮叨一下~
4ye 在網上搜這個 fail-fast 和 fail-safe 的區別時,看到下面這張圖。
幾乎都在說 fail-safe 會複製原來的集合,然後在複製出來的集合上進行操作,然後就說這樣是不會拋出 ConcurrentModificationException 異常了。
可是這種說法是 不嚴謹的~ 它描述的情況應該是針對這個 CopyOnWriteArrayList 或者 CopyOnWriteArraySet 的情況(下面的源碼講到~)
CopyOnWriteArrayList 源碼
可以發現這裡 snapshot 的指針是始終指向這個原陣列的(當你創建迭代器的時候)
當你新增資料時,它會複製原來的陣列,並在複製出來的陣列上進行修改,
然後再設定進去,可以發現至始至終都沒有修改到這個原陣列,
所以迭代器中的資料是不受影響的~
fail-safe 也是得具體情況具體分析的。
嘿嘿 現在回答上面那個 為啥可以 remove 的問題啦~
重點在紅框處, pred 為 null 表示是陣列的頭部,此時呼叫 setEntryAt ,這裡也是出現了這個 UNSAFE
UNSAFE.putOrderedObject 這段程式碼的意思就是 :
有序的(有延遲的) 強制 更新資料到 主記憶體。(不能立刻被其他執行緒發現)
這些 和 Java 的 JMM (Java記憶體模型)有關!
java.util 包下的屬於fail-fast ,
特點:
不允許併發修改,如果併發修改的話會導致在迭代過程中拋出 ConcurrentModificationException ,
出發點是 modCount != expectedModCount 。
java.util.concurrent 包下的 屬於 fail-safe ,
特點:
允許併發修改,但是 無法保證在迭代過程中獲取到最新的值 。
concurrentHashMap 獲取和修改資料時 ,是通過 UNSAFE 類 直接從主記憶體中獲取或者更新資料到主記憶體~
CopyOnWriteArrayList 或者 CopyOnWriteArraySet ,就直接 複製原來的集合,然後在複製出來的集合上進行操作
。
相關文章
原文連結:https://mp.weixin.qq.com/s/dPA7zohM2LfBrZT-sfQnyg你真的瞭解 fail-fast和 fail-safe嗎?簡介java.util 包下的 屬於 fail-fast , 快速失敗~ java.util.concurrent
2021-09-06 03:03:41
在日常工作中經常會用到Excel軟體,在收到的一些表格資料中,有不同的空行,為了表格的美觀性可以刪除這些空行,今天小編就來分享下如何快速刪除這些空行。1、以下圖中的表格資料為
2021-09-06 03:03:14
在家電空調領域,最出名的兩個品牌應該就是格力、美的了。在過去的許多年,這兩家企業也是鬥得很厲害,似乎充滿著恩怨情仇,因為董明珠就經常噴美的,吐槽美的。不過在雙方競爭的過程
2021-09-06 03:03:00
7月底,華為釋出了HUAWEI P50系列。與其前代不同的是,新陣容不僅限於4G,還配備了高通SoC。現在,據可靠訊息人士透露,該公司未來將使用更多高通晶片組。根據國外科技媒體的說法,除了
2021-09-06 03:02:54
2021年9月1日,三星新一代摺疊屏產品Galaxy Z Fold3 5G與Galaxy Z Flip3 5G正式在國內釋出。與此同時,三星專為本次新品打造的20餘家三星全新摺疊屏手機快閃店,也已陸續在上海、
2021-09-06 03:02:46
據中國日報網訊息,騰訊擬推出個人微信雲端儲存付費服務,意味著微信聊天記錄可以實現雲端備份和恢復。 此訊息一出,立刻登上微博熱搜,引起千萬網友熱烈討論。微信越來越成為大多
2021-09-06 03:02:41