fail-fast

fail-fast機制

- java集合(Collection)中的一種錯誤機制
- 當多個線程對同一個集合的內容進行操作時,就可能產生fail-fast事件
- 只能用來檢測錯誤
  • 測試代碼
    public class Test {
    
        private static List<String> list = new ArrayList<>();
    
        /**
        * @Description:  打印list內容
        */
        public static void showAll(){
            System.out.println("\nnum is ");
            String num = null;
            Iterator iterator = list.iterator();
            while(iterator.hasNext()){
                num = (String) iterator.next();
                System.out.print(num + " ");
            }
        }
    
        /**
        * @Description: 往list中添加數據,並打印list中數據
        */
        public static class ThreadOne extends Thread{
            public void run(){
                int index = 0;
                while(index < 10){
                    list.add(String.valueOf(index));
                    showAll();
                    ++index;
                }
            }
        }
    
        public static class ThreadTwo extends Thread{
            public void run(){
                int index = 10;
                while(index < 20){
                    list.add(String.valueOf(index));
                    showAll();
                    ++index;
                }
            }
        }
    
        public static void main(String[] args) {
            // 同時啓動兩個線程操作list
            new ThreadOne().start();
            new ThreadTwo().start();
        }
    }
    
    • 運行代碼。拋出異常java.util.ConcurrentModificationException,即fail-fast事件
    • 若想在多線程環境下使用fail-fast機制的集合
      // 原代碼
      private static List<String> list = new ArrayList<String>();
      // 修改爲
      private static List<String> list = new CopyOnWriteArrayList<String>();
      
  • fail-fast原理
    • ArrayList的Iterator是在父類AbstractList.java中實現
      package java.util;
      public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
      
          /**
           * 部分源碼
           */
      
          // 記錄List修改的次數:每一次添加/刪除等操作,將modCount+1
          protected transient int modCount = 0;
      
          // 返回List對應迭代器。實際上,是返回Itr對象。
          public Iterator<E> iterator() {
              return new Itr();
          }
      
          // Itr是Iterator(迭代器)的實現類
          private class Itr implements Iterator<E> {
              int cursor = 0;
      
              int lastRet = -1;
      
              // 修改數的記錄值。
              // 每次新建Itr()對象時,都會保存新建該對象時對應的modCount;
              // 以後每次遍歷List中的元素的時候,都會比較expectedModCount和modCount是否相等
              // 若不相等,則拋出ConcurrentModificationException異常,產生fail-fast事件
              int expectedModCount = modCount;
      
              public boolean hasNext() {
                  return cursor != size();
              }
      
              public E next() {
                  // 獲取下一個元素之前,都會判斷“新建Itr對象時保存的modCount”和“當前的modCount”是否相等;
                  // 若不相等,則拋出ConcurrentModificationException異常,產生fail-fast事件。
                  checkForComodification();
                  try {
                      E next = get(cursor);
                      lastRet = cursor++;
                      return next;
                  } catch (IndexOutOfBoundsException e) {
                      checkForComodification();
                      throw new NoSuchElementException();
                  }
              }
      
              public void remove() {
                  if (lastRet == -1)
                      throw new IllegalStateException();
                  checkForComodification();
      
                  try {
                      AbstractList.this.remove(lastRet);
                      if (lastRet < cursor)
                          cursor--;
                      lastRet = -1;
                      expectedModCount = modCount;
                  } catch (IndexOutOfBoundsException e) {
                      throw new ConcurrentModificationException();
                  }
              }
      
              final void checkForComodification() {
                  if (modCount != expectedModCount)
                      throw new ConcurrentModificationException();
              }
          }
      }
      
    • ArrayList源碼,modCount被修改
      package java.util;
      
      public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
      {
      
          /**
           * 部分源碼
           */
           
          // list中容量變化時,對應的同步函數
          public void ensureCapacity(int minCapacity) {
              modCount++;
              int oldCapacity = elementData.length;
              if (minCapacity > oldCapacity) {
                  Object oldData[] = elementData;
                  int newCapacity = (oldCapacity * 3)/2 + 1;
                  if (newCapacity < minCapacity)
                      newCapacity = minCapacity;
                  // minCapacity is usually close to size, so this is a win:
                  elementData = Arrays.copyOf(elementData, newCapacity);
              }
          }
      
      
          // 添加元素到隊列最後
          public boolean add(E e) {
              // 修改modCount
              ensureCapacity(size + 1);  // Increments modCount!!
              elementData[size++] = e;
              return true;
          }
      
      
          // 添加元素到指定的位置
          public void add(int index, E element) {
              if (index > size || index < 0)
                  throw new IndexOutOfBoundsException(
                  "Index: "+index+", Size: "+size);
      
              // 修改modCount
              ensureCapacity(size+1);  // Increments modCount!!
              System.arraycopy(elementData, index, elementData, index + 1,
                   size - index);
              elementData[index] = element;
              size++;
          }
      
          // 添加集合
          public boolean addAll(Collection<? extends E> c) {
              Object[] a = c.toArray();
              int numNew = a.length;
              // 修改modCount
              ensureCapacity(size + numNew);  // Increments modCount
              System.arraycopy(a, 0, elementData, size, numNew);
              size += numNew;
              return numNew != 0;
          }
         
      
          // 刪除指定位置的元素 
          public E remove(int index) {
              RangeCheck(index);
      
              // 修改modCount
              modCount++;
              E oldValue = (E) elementData[index];
      
              int numMoved = size - index - 1;
              if (numMoved > 0)
                  System.arraycopy(elementData, index+1, elementData, index, numMoved);
              elementData[--size] = null; // Let gc do its work
      
              return oldValue;
          }
      
          // 快速刪除指定位置的元素 
          private void fastRemove(int index) {
      
              // 修改modCount
              modCount++;
              int numMoved = size - index - 1;
              if (numMoved > 0)
                  System.arraycopy(elementData, index+1, elementData, index,
                                   numMoved);
              elementData[--size] = null; // Let gc do its work
          }
      
          // 清空集合
          public void clear() {
              // 修改modCount
              modCount++;
      
              // Let gc do its work
              for (int i = 0; i < size; i++)
                  elementData[i] = null;
      
              size = 0;
          }
      }        
      
    • 可以發現涉及到修改集合中的元素個數時,都會改變modCount的值

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章