1. 程式人生 > >Java集合-05fail-fast(快速失敗)機制原理及解決方法

Java集合-05fail-fast(快速失敗)機制原理及解決方法

fail-fast簡介

fail-fast(快速失敗),是Java集合的一種錯誤檢測機制。當在遍歷集合的過程中該集合在結構(改變集合大小)上發生變化時候,
有可能發生fail-fast,丟擲java.util.ConcurrentModificationException異常。

fail-fast出現場景

  • 單執行緒場景
    •     public class FailFastSingleThreadTest {
              public static void main(String[] args) {
                  List<String> lists = new ArrayList<>(10);
                  for (int i = 0; i < 4; i++){
                      lists.add(String.valueOf(i));
                  }
      
                  //fail-fast
                  for (String list : lists) {
                      lists.remove(3);
                  }
              }
          }
      //output:Exception in thread "main" java.util.ConcurrentModificationException
  • 多執行緒場景
    •   public class FailFastMultiThread  {
            private static List<String> lists = new ArrayList<>(10);
            static {
                for (int i = 0; i < 4; i++){
                    lists.add(String.valueOf(i));
                }
            }
            public static void main(String[] args) {
                new Thread(new ForEachThread()).start();
                new Thread(new EditThread()).start();
            }
      
            //用於遍歷
            static class ForEachThread implements Runnable{
                @Override
                public void run() {
                    Iterator<String> iterator = lists.iterator();
                    while (iterator.hasNext()){
                        System.out.println(iterator.next());
                        try {
                            Thread.sleep(100);//為了另外的執行緒加入,也是為了結合在遍歷時候修改結構
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
      
                }
            }
      
            //用於修改結構
            static class EditThread implements Runnable{
                @Override
                public void run() {
                    lists.add("8");
                }
            }
      
        }
        //output:Exception in thread "Thread-0" java.util.ConcurrentModificationException

      產生原因

      集合能夠遍歷是因為迭代器的原因,而Iterator介面只是定義了具體的方法,集合需要實現該介面方法,
      檢視ArrayList中具體的實現方法

        //省略部分方法
        private class Itr implements Iterator<E> {
            int cursor;       // index of next element to return
            int lastRet = -1; // index of last element returned; -1 if no such
            int expectedModCount = modCount;
      
            @SuppressWarnings("unchecked")
            public E next() {
                checkForComodification();
                int i = cursor;
                if (i >= size)
                    throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i + 1;
                return (E) elementData[lastRet = i];
            }
      
            public void remove() {
                if (lastRet < 0)
                    throw new IllegalStateException();
                checkForComodification();
      
                try {
                    ArrayList.this.remove(lastRet);
                    cursor = lastRet;
                    lastRet = -1;
                    expectedModCount = modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }
      
      
      
            final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
        }

      可以看出在Itr是ArrayList的一個內部類,迭代器操作通過這個內部類,Itr有個expectedModCount屬性,這個屬性判斷是否與modCount相等,如果不相等丟擲異常,modCount記錄list結構上發生變化的次數,可以看出在迭代時候checkForComodification()方法檢測兩個的值不相等就丟擲異常

解決方法

  • 單執行緒
    • 使用迭代器的remove方法
      public class NoFailFastSingleThread {
          public static void main(String[] args) {
              List<String> lists = new ArrayList<>(10);
              for (int i = 0; i < 4; i++){
                  lists.add(String.valueOf(i));
              }
    
              Iterator<String> iterator = lists.iterator();
              while (iterator.hasNext()){
                  String next = iterator.next();
                  if (next != null){
                      iterator.remove();
                  }
              }
    
          }
      }
  • 多執行緒
    • 使用java併發包下的類來代替對應的集合,如CopyOnWriteArrayList代替ArrayList,