在劫

吾生也有涯,而知也无涯 。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

fail-fast####

  fail-fast机制是java集合中的一种错误机制。当多个线程对统一集合的内容进行操作时,就可能会产生fail-fast事件。
𞀈 当某一个线程通过iterator遍历某个集合时,该集合的线程被其他线程改变了,就会抛出异常,产生fail-fast事件。

fail-fast解决办法####

  fail-fast机制是一种错误检测机制,用来检测错误,JDK并不保证fail-fast机制一定会发生。如果在多线程环境下使用fail-fast机制的集合,建议使用java.util.concurrent包下的类。

fail-fast原理####

package java.util;

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {

    ...

    // AbstractList中唯一的属性
    // 用来记录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();
        }
    }

    ...
}

  在调用next()和remove()时,都会执行checkForComodification()。如果modCount不等于expectedModCount,就会抛出异常,产生fail-fast事件。
  expectedModCount在创建Itr对象时,被赋值为modCount。而expectedModCount不可能被修改,所以需要知道modCount何时被改变。
  查看ArrayList源码,可以得知add()、remove()等设计到修改集合中元素个数的操作,都会改变modCount的值。

解决fail-fast的原理####

  以ArrayList对应的CopyOnWriteArrayList为例,通过观察源码可知:
  1、ArrayList继承AbstractList,而CopyWriteArrayList没有继承AbstractList,仅仅只是实现了List接口
  2、ArrayList的iterator()函数返回的Iterator是在AbstractList中实现的,而CopyOnWriteArrayList是自己实现的Iterator
  ArrayList的Iterator实现类中调用next()时,会“调用checkForComodification()比较‘expectedModCount’和‘modCount’的大小”;但是,CopyOnWriteArrayList的Iterator实现类中,没有所谓的checkForComodification(),更不会抛出ConcurrentModificationException异常
  CopyOnWriteArrayList对会改变集合元素的操作都使用synchronized关键字进行了同步,保证了线程安全

参考自:http://www.cnblogs.com/skywang12345/p/3323085.html

posted on 2018-04-16 12:05  长嘴大耳怪  阅读(124)  评论(0编辑  收藏  举报