什麼是fail-fast機制,怎樣避免fail-fast機制?


什麼是fail-fast機制,怎樣避免fail-fast機制?

什麼是fail-fast機制

如果我們對一個集合進行遍歷,而在集合遍歷的過程中對其進行修改(增加、刪除、修改)

或者 一個線程在對結合進行過遍歷,另外一個線程對其修改,則會報ConcurrentModificationException 異常。

舉例說明fail-fast 機制

  1. 場景: 單線程環境下,遍歷的時候,進行刪除
什麼是fail-fast機制,怎樣避免fail-fast機制?

測試結果如下:


什麼是fail-fast機制,怎樣避免fail-fast機制?

2、場景2: 多線程環境下,一個對集合進行遍歷元素。一個對集合刪除元素

什麼是fail-fast機制,怎樣避免fail-fast機制?

測試結果:


什麼是fail-fast機制,怎樣避免fail-fast機制?

3、場景3-對ArrayList 的subList進行操作

參考如下:

fail-fast 機制 為什麼會出現ConcurrentModificationException異常

我們先看下Iterator 類:

1、ArrayList 的add、set 等操作都會進行modCount++;

什麼是fail-fast機制,怎樣避免fail-fast機制?

什麼是fail-fast機制,怎樣避免fail-fast機制?

2、調用list.iterator時會new Itr();

創建Itr的過程,保存了 ArrayList中的modeCount,每次進行遍歷list的時候都會調用

checkForComodification方法:


什麼是fail-fast機制,怎樣避免fail-fast機制?

上面檢查 expectedModCount和modCount是否相等,若不相等,則拋出異常

所以說在循環的時候對list進行remove, expectedModCount和modCoun不相等,所以會報異常(場景1),

3、為什麼多線程場景下也會出現ConcurrentModificationException 異常

上面的場景2,兩個線程初始化時,都持有list的modCount,當一個線程在遍歷,一個線程在刪除,

也會導致 expectedModCount和modCoun不相等。


怎麼解決fail-fast 出現的異常


1、在單線程環境下,我們可以不調用集合的remove方法,可以調用 Iterator的remove方法。


什麼是fail-fast機制,怎樣避免fail-fast機制?

為什麼可以調用 Iterator 的remove方法呢?


什麼是fail-fast機制,怎樣避免fail-fast機制?

從上面源碼可以看出,每次remove並不會修改modCount值,因為 每次remove只remove遍歷過的元素,所以不會發生fail-fast。


2、在多線程環境下,使用concurrent下的併發類

比如: 我們使用CopyOnArrayList 來代替 ArrayList,用ConcurrentHashMap 代理 HashMap

CopyOnArrayList參考下面文章。


什麼是fail-fast機制,怎樣避免fail-fast機制?

使用 CopyOnArrayList 需要注意一下事項:

  • 初始化 設置合理的初始如果能量,因為擴容的代價非常大
  • 使用批量的添加(addAll)或者批量刪除(removeAll)操作,這個可以避免每次添加都會元素
  • CopyOnArrayList只能保證最終一致性,不能保證每次讀取都是最新數據


總結

1、java.util 下的所有集合類都是fail-fast

2、concurrent 下的所有集合類都是fail-safe

3、在多線程環境下,儘量使用 concurrent 下的集合類


分享到:


相關文章: