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,
posted @ 2018-12-18 14:11  Jzedy  阅读(969)  评论(0编辑  收藏  举报