快速迭代机制失败不能保证的原因

Posted 风泊月

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快速迭代机制失败不能保证的原因相关的知识,希望对你有一定的参考价值。

当使用foreach或Iterator迭代器遍历集合时,同时调用迭代器自身以外的方法修改了集合的结构,例如调用集合的add和remove方法时,就会报ConcurrentModificationException。
但是,迭代器的快速失败行为不能得到保证,一般来说,存在不同步的并发修改时,不可能作出任何坚决的保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException*。例如:

ArrayList<String> list = new ArrayList<>();
		list.add("安琪拉");
		list.add("妲己");
		list.add("嬴政");
		list.add("项羽");
		
        //以下代码没有发生ConcurrentModificationException异常
		Iterator<String> iterator = list.iterator();
		while(iterator.hasNext())
			String str = iterator.next();
			
			if("嬴政".equals(str))
				list.remove(str);
			
		

为什么呢?

想要知道原因 必须清楚一点 就是在 迭代器调用时 next()会触发并发修改异常



  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;

        Itr() 

        public boolean hasNext() 
            return cursor != size;
        

        @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();
        
    

而在删除倒数第二个元素时 会导致size减少 不会再去执行next() 看源码

ArrayList<String> list = new ArrayList<>();
		list.add("安琪拉");
		list.add("妲己");
		list.add("嬴政");
		list.add("项羽");
		
        //以下代码没有发生ConcurrentModificationException异常
		Iterator<String> iterator = list.iterator();
		while(iterator.hasNext())
			String str = iterator.next();
			
			if("嬴政".equals(str))
			//注意这个 remove() 调用后
				list.remove(str);
			
		
		//会调用ArrayList 此方法 因为 o不为null 执行else
 public boolean remove(Object o) 
        if (o == null) 
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) 
                    fastRemove(index);
                    return true;
                
         else 
       
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) 
                 //走这里
                    fastRemove(index);
                    return true;
                
        
        return false;
    

	//调用了此方法 删除了 嬴政 
  private void fastRemove(int index) 
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
         // 将size -1
        elementData[--size] = null; // clear to let GC do its work
    
//因此 循环回去之后 再进行校验  再次调用此hasNext()
        while(iterator.hasNext())
			String str = iterator.next();
			
			if("嬴政".equals(str))
			//注意这个 remove() 调用后
				list.remove(str);
			
		

        public boolean hasNext() 
        //因为size 已经减-1 与下标的值相同 返回false 结束迭代器遍历 不会再执行next() 因此不会报错
            return cursor != size;
        
        

以上是关于快速迭代机制失败不能保证的原因的主要内容,如果未能解决你的问题,请参考以下文章

快速迭代机制失败不能保证的原因

快速迭代机制失败不能保证的原因

抛出 ConcurrentModificationException异常(fastfail快速失败机制)分析解决

抛出 ConcurrentModificationException异常(fastfail快速失败机制)分析解决

fail-fast机制

Java集合框架中的快速失败(fail—fast)机制详解