java fail-fast 快速失败机制

2018-04-04  本文已影响52人  tracy_668

快速失败,fail-fast,它是java集合的一种错误检测机制,当多个线程对集合进行结构上的改变的操作时,有可能产生fail-fast,它是为了防止多线程修改集合造成并发问题。

当方法检测到对象的并发修改,但不允许这种修改时就会抛出concurrentmodificationexception,该异常不会指出对象已经由不同线程并发修改,如果单线程违反了规则,同样会抛出该异常。fail-fast是在操作迭代器时产生的,我们看一下ArrayList迭代器的源码:

迭代器在调用next(), remove()方法时都是调用checkForComodification()方法,该方法就是检测modcount==expectedmodcount?,若不等则抛出concurrentmodificationexception异常,modcount和expectedmodcount,是在什么时候改变的呢?

expectedmodcount是在itr中定义的,int expectedModCount = ArrayList.this.modCount,expectedmodcount 的值不会改变,会变的是modcount,modcount是在AbstractList中定义的,在ArrayList中无论add、remove、clear方法只要是涉及了改变ArrayList元素个数的方法都会导致modcount的改变。

单线程下抛出该异常可以通过itr的remove方法来避免,Itr中的remove方法实际上也是调用了ArrayList的remove,但增加了expectedmodcount=modcount;保证了不会抛出该异常。但Itr只有remove方法,add,clear等方法没有。该方法只适合单线程。

多线程环境下解决方案:

1: 迭代前加锁

2: 使用CopyOnWriteArrayList来替换ArrayList,它是ArrayList的一个线程安全的变体。其所有对元素有变化的操作都是通过对底层数组进行一次新的复制来实现的。它非常适合在不想进行同步遍历但又需要从并发线程中排除冲突或者当遍历操作的数量大大超过改变集合结构操作的次数时使用。

CopyOnWriteArrayList不会产生concurrentmodificationexception,它没有像ArrayList中使用checkformodification方法来判断expectedmodcount与modcount是否相等。

其add方法copy原来的array,在copy后的数组上进行添加操作。其核心思想是:任何对array结构改变的操作(add, remove)CopyonWriteArrayList都会copy之前的array,再在copy后的array上修改,修改后改变原来数组的引用。付出的代价就是产生大量的对象,数组的copy也比较耗时。

上一篇下一篇

猜你喜欢

热点阅读