美文网首页
FailFast机制

FailFast机制

作者: 我是许仙 | 来源:发表于2020-09-22 14:59 被阅读0次

    表象

    开启2个线程操作同一个Arrylist,一个线程A添加数据同时另一个线程B获取数据。

    public class FailFast {
    
        public static List<Integer> list = new ArrayList<>();
    
        public static void main(String[] args) {
    
            new Thread(() -> {
                for (int i = 0; i < 1000; i++) {
                     list.add(i);
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    
    
            new Thread(() -> {
                for (Iterator<Integer> integerIterator = list.iterator(); integerIterator.hasNext();) {
                    Integer integer = integerIterator.next();
                    try {
                        Thread.sleep(5);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(integer);
                }
    
            }).start();
        }
    }
    

    结果

    image-20200922143710036.png

    结论

    fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。

    源码解析

    for (Iterator<Integer> integerIterator = list.iterator(); integerIterator.hasNext();) {
        //在这里获取了迭代器中的返回数据
        Integer integer = integerIterator.next();
    

    Arrylist

    @SuppressWarnings("unchecked")//这个注解的意思是清除 unchecked异常检查
    public E next() {
        //核心逻辑
        checkForComodification();
        ....
    }
    //最终抛出异常的地方
    final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
     }
    

    这里对比的是2个数据 modCount != expectedModCount,如果不相等则抛出异常

    expectedModCount来源

    ArryList

    
    public Iterator<E> iterator() {
        return new Itr();
    }
    
     private class Itr implements Iterator<E> {
           ....
            //1 核心代码  对变量赋值
            int expectedModCount = modCount;
    
            public boolean hasNext() {
                return cursor != size;
    }
    

    可以看到Arrylist内部定义了一个迭代器,在new一个迭代器的过程中,modCount的值赋值给 expectedModCount

    modCount来源

    ArryList

    //属性变量
    protected transient int modCount = 0;
    
    //add操作
     private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
    }
    //remove操作
      public E remove(int index) {
           ...
            modCount++;
            ...
    }
    
    总结

    在集合中的任何操作都会导致 modCount变量自增,而当我们声明一个迭代器的时候,他会初始化一个值expectedModCount = modCount 。当用另一个线程操作集合导致modCount自增,而expectedModCount的值不会改变,最终在查询的时候会导致 if (modCount != expectedModCount) 代码不成立从而抛出异常。

    相关文章

      网友评论

          本文标题:FailFast机制

          本文链接:https://www.haomeiwen.com/subject/mluwyktx.html