集合中的快速失敗(fail-fast)與安全失敗(fail-safe)

什麼是fail-fast(快速失敗)

在用迭代器遍歷集合時,當集合的結構被修改,會拋出ConcurrentModificationException異常。java

java.util包下的集合類都是快速失敗的, 常見的的使用fail-fast方式遍歷的容器有HashMapArrayList等。安全

fail-fast(快速失敗)

  • 什麼狀況會出現fail-fast(快速失敗)?

    1.單線程環境
    集合在遍歷的過程當中,若是要對集合進行增刪操做,沒有調用迭代器的方法,而是用的集合自身的方法,則可能會產生fail-fast(快速失敗)
    2.多線程環境下
    當一個線程在遍歷某個集合的過程當中,另外一個線程對集合的結構進行了修改,則可能產生fail-fast(快速失敗)

    多線程

  • 具體效果咱們看以下代碼:spa

    ArrayList arrayList = new ArrayList();
           arrayList.add("a");
           arrayList.add("c");
           arrayList.add("d");
    
           Iterator iterator = arrayList.iterator();
           while (iterator.hasNext()) {
               System.out.println(iterator.next());
               arrayList.add("e"); ①
               System.out.println("此時 arrayList 長度爲" + arrayList.size());
           }

    執行後的效果以下圖:

    線程

    image.png

    當迭代器在遍歷時,不對arrayList進行修改,也就是刪除①時。

    image.png3d

    當迭代器在遍歷時,對arrayList進行修改,也就保留①處代碼。就會拋出 ConcurrentModificationException 異常

    code

  • 爲何在用迭代器遍歷時,修改集合就會拋異常?
  1. 緣由是迭代器在遍歷時直接訪問集合中的內容,而且在遍歷過程當中使用一個modCount變量。集合在被遍歷期間若是內容發生變化,就會改變modCount的值。
  2. 每當迭代器使用hashNext()/next()遍歷下一個元素以前,都會檢測modCount變量是否爲 expectedModCount值,是的話就返回遍歷;不然拋出異常,終止遍歷。

什麼是安全失敗(fail-safe)

採用安全失敗的集合容器,在遍歷時不是直接在集合內容上訪問的,而是先複製原有集合內容,在拷貝的集合上進行遍歷,因此對原集合的修改並不會被迭代器檢測到對象

因爲迭代時是對原集合的拷貝進行遍歷,因此在遍歷過程當中對原集合所做的修改並不能被迭代器檢測到,因此不會拋 ConcurrentModificationException異常。blog

java.util.concurrent包下面的全部的類都是安全失敗的,如ConcurrentHashMap, CopyOnWriteArrayListhash

  • 具體效果咱們看以下代碼:

    ConcurrentHashMap concurrentHashMap = new ConcurrentHashMap();
           concurrentHashMap.put("a", 1);
           concurrentHashMap.put("b", 2);
           concurrentHashMap.put("c", 3);
    
           Set set = concurrentHashMap.entrySet();
           Iterator iterator = set.iterator();
    
           while (iterator.hasNext()) {
               System.out.println(iterator.next());
               concurrentHashMap.put("d", 4); ②
           }
           System.out.println("結束");
       }

    執行後的效果以下圖:

    image.png

    當迭代器在遍歷時,對concurrentHashMap進行修改時,也就②。並未拋出任何異常

  • 爲何在用迭代器遍歷時,修改集合不會拋異常?

    因爲迭代時是對原集合的拷貝進行遍歷,內部都是保存了該集合對象的一個快照副本,而且沒有modCount等數值作檢查。

    總結

    fail-safe(安全失敗)容許在遍歷的過程當中對容器中的數據進行修改,而fail-fast(快速失敗)則不容許。

相關文章
相關標籤/搜索