Java中的fail-fast機制

什麼是fail-fast機制

fail-fast是一種錯誤檢測機制,一般意義上的fail-fast是當我們的代碼可能出現異常情況時,會立即拋出異常並中斷執行,而不是繼續執行。相反就是fail-safe機制。

在java中的fail-fast機制通常是指在集合中使用迭代器遍歷時,當多個線程對同一集合進行操作時,就可能會產生fail-fast。比如當一個線程A通過迭代器正在遍歷集合時,另一個線程又對該集合中的內容進行了修改,那麼線程A在訪問集合時,就會拋出ConcurrentModificationException異常,產生fail-fast機制。而採用fail-safe機制的集合在遍歷時任何對集合內容的修改都會先複製一份原來,在複製的集合上進行修改,不影響原來的,所以不會拋出ConcurrentModificationException

在java中,線程不安全的集合類的迭代器實現一般都是fail-fast的,如HashMap,ArrayList等,而線程安全的集合是fail-safe的,如CopyOnWriteArrayList,ConcurrentHashMap

fail-fast實現機制

在java中,fail-fast是如何實現的呢?比如在ArrayList等集合中,都會維護一個modCount變量,當對集合進行增刪等操作時,就會將modCount值加1。在迭代器中,會有一個expectedModCount,初始化設爲modCount的值,在使用迭代器調用next,remove等方法時,會先調用函數checkForComodification()檢查這兩個值是否相等,不相等就拋出ConcurrentModificationException異常。

後續當一個線程在使用迭代器進行遍歷時,另一個線程如果對集合做了修改,則會使modCount的值和expectedModCount的值不相等,則會拋出ConcurrentModificationException異常,導致fail-fast.

源碼如下:
在這裏插入圖片描述
在這裏插入圖片描述

CopyOnWriteArrayList解決fail-fast

CopyOnWriteArrayList是juc包下的一個線程安全的集合,在需要同步的ArrayList時,可採用CopyOnWriteArrayList來替換Vector。使用CopyOnWriteArrayList集合進行遍歷時不會產生fail-fast,即其是fail-safe的,其基本思想是每次對集合進行修改時都會拷貝一份原數組的副本,在拷貝的數組上進行修改,然後將原數組的指針指向拷貝後的。所以在當一個線程A對集合遍歷時,另一個線程修改了集合,但線程A不會看到修改後的內容,所以不會發生fail-fast。

對比ArrayList和CopyOnWriteArrayList的源碼:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

可以看到CopyOnWriteArrayList中進行增刪等修改操作時,都是先複製一份原來的數組,然後對複製的數組修改後再將原數組的指針指向複製的數組setArray

查看CopyOnWriteArrayList迭代器源碼:
在這裏插入圖片描述
在這裏插入圖片描述

總結

Copy-On-Write是一種延時懶惰策略的思想,是寫時複製的容器。CopyOnWriteArrayList中add/remove等寫方法是需要加鎖的,目的是爲了避免Copy出N個副本出來,導致併發寫。但是,CopyOnWriteArrayList中的讀方法是沒有加鎖的。所以可以進行併發讀,但是讀到的數據可能不是最新的。所以CopyOnWrite容器是一種讀寫分離的思想,讀和寫不同的容器。而Vector在讀寫的時候使用同一個容器,讀寫互斥,同時只能做一件事兒。

參考:

  1. https://www.cnblogs.com/skywang12345/p/3308762.html
  2. https://juejin.im/post/5cb683d6518825186d65402c
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章