GVKun编程网logo

子列表抛出ConcurrentModificationException(输出列表中的子列表)

26

如果您对子列表抛出ConcurrentModificationException和输出列表中的子列表感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解子列表抛出ConcurrentModifica

如果您对子列表抛出ConcurrentModificationException输出列表中的子列表感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解子列表抛出ConcurrentModificationException的各种细节,并对输出列表中的子列表进行深入的分析,此外还有关于ArrayList什么情况会抛出ConcurrentModificationException、ConcurrentModificationException、ConcurrentModificationException 源码解析、ConcurrentModificationException异常的实用技巧。

本文目录一览:

子列表抛出ConcurrentModificationException(输出列表中的子列表)

子列表抛出ConcurrentModificationException(输出列表中的子列表)

我有非常简单的代码:

    List<String> list = new ArrayList<String>();    String a = "a";    String b = "b";    String c = "c";    String d = "d";    list.add(a);    list.add(b);    list.add(c);    List<String> backedList = list.subList(0, 2);    list.add(0, d);     System.out.println("2b: " + backedList);

我通过list.add(0,d)得到ConcurrentModificationException异常。所以总的来说,这是因为sublist()造成的。我很困惑,因为在sublist()的情况下,文档中说:

返回列表由该列表支持,因此返回列表中的非结构性更改会反映在此列表中, 反之亦然

您能解释一下渔获量在哪里吗?

答案1

小编典典

subList是原始列表的简单视图(请参阅此处)。您可以更改其中的元素,但不能更改列表的结构。

根据文档,subList如果您尝试进行结构更改,则行为是不确定的。我猜在这个特定的实现中,它ConcurrentModificationException被确定为不确定的行为。

如果后备列表(即,此列表)以非通过返回列表的方式进行了结构修改,则此方法返回的列表的语义将变得不确定。(结构修改是指更改此列表的大小的结构修改,或者以其他方式扰乱此列表的方式,使得正在进行的迭代可能会产生错误的结果。)

ArrayList什么情况会抛出ConcurrentModificationException

ArrayList什么情况会抛出ConcurrentModificationException

近日,在看ArrayList的源码实现。发现很多情况会抛出ConcurrentModificationException。下面总结一下大致发生的情况。 首先,ArrayList不是线程安全的。 首先来看一个例子:

    public  static  void main(String[] args){
        List<Integer> aList = new ArrayList<Integer>();
        aList.add(1);
        aList.add(2);

        Iterator<Integer> iter = aList.iterator();
        aList.add(3);
        System.out.println(iter.next());
    }

运行结果:

Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
	at java.util.ArrayList$Itr.next(ArrayList.java:831)
	at com.zhu.util.ArrayIistIteratorTest.main(ArrayIistIteratorTest.java:19)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

由例子可见,在调用iterator方法后,如果其他线程对ArrayList进行了更改大小的操作,如add和remove。那么将会抛出ConcurrentModificationException。字面意思很简单:并发修改异常。

我们通过源码,来看看为什么会出现这样的情况: 首先ArrayList的iterator方法实现:

public Iterator<E> iterator() {
        return new Itr();
    }

Itr是ArrayList的内部类,实现了Iterator<E>接口,下面是Itr的源码:

private class Itr implements Iterator<E> {
        /**
         * Index of element to be returned by subsequent call to next.
         */
        int cursor = 0;

        /**
         * Index of element returned by most recent call to next or
         * previous.  Reset to -1 if this element is deleted by a call
         * to remove.
         */
        int lastRet = -1;

        /**
         * The modCount value that the iterator believes that the backing
         * List should have.  If this expectation is violated, the iterator
         * has detected concurrent modification.
         */
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size();
        }

        public E next() {
            checkForComodification();
            try {
                int i = cursor;
                E next = get(i);
                lastRet = i;
                cursor = i + 1;
                return next;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }

        public void remove() {
            if (lastRet < 0)
                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();
        }
    }

Itr只有三个成员变量:cursor,lastRet,exceptdModCount

  • cursor:next方法应该返回元素所在的下标
  • lastRet:上一次next返回元素的下标
  • exceptedModCount:ArrayList成员变量modCount的副本 ArrayList中modCount的意义是记录当前ArrayList被修改的次数,ArrayList中会引起modCount发生改变的方法有以下集中:
    1. trimToSize:将数组大小减小至当前元素个数
    2. ensureCapacity:容量设置
    3. add:新增元素的时候
    4. remove:移除元素的时候
    5. clear:清空的时候 所有移除和新增的操作都会引起modCount的修改

可以看出引起例子抛出异常的原因是因为Itr创建之后,exceptedModCount为当时ArrayList对象modCount的值。在Itr的next和remove方法中可以看出,在世纪操作之前都会调用checkForComodification来检查ArrayList是否被修改过。在调用Itr中next和remove与Itr创建之间,如果有其他线程或本线程调用了引起ArrayList的modCount发生变化的操作,那么将会抛出并发修改异常。

那么下面我们再来看看还有其他什么情况,ArrayList会抛出CurrentModificationException。

  1. writeObject:writeObject是序列化时调用的方法,也就是说在在元素序列化时,如果有其他操作引起了modCount发生改变时会抛出并发修改异常。
  2. Itr的next和remove:在使用迭代器期间,其他操作引起modCount改变时。
  3. ListItr的previous,next,set,remove,add:同Itr.
  4. SubList中的所有操作

ConcurrentModificationException

ConcurrentModificationException

This is a result of concurrent iteration and modification. It is pretty
hard to define and implement what should happen if an iterated-over
collection is modified. That''s why Java''s iterators are typically
designed so that they immediately fail when the underlying collection is
modified. The JavaDoc for ArrayList, e.g., has to say the following:


The iterators returned by this class''s iterator and listIterator methods
are fail-fast: if list is structurally modified at any time after the
iterator is
created, in any way except through the iterator''s own remove or add
methods, the iterator will throw a ConcurrentModificationException.
Thus, in the
face of concurrent modification, the iterator fails quickly and cleanly,
rather than risking arbitrary, non-deterministic behavior at an
undetermined time
in the future.

撰写多线程代码时,你遇到过多少次下面的提示:
Exception in thread "main" java.util.ConcurrentModificationException 


这个异常产生的原因有几个。一是直接对集合调用删除操作而不是在枚举器上。二是不同的线程试图对集合进行增删操作的时候。

这个解决办法的第一步就是同步代码,使得你在枚举的时候其它的线程不能增删记录。但是如果每个枚举过程要进行复杂的计算或者是数据库访问的一部分的话,这个同步就会导致可怕的后果。为了减少负面影响,可以拷贝一个只读的枚举器,去掉同步,然后采用下列代码所示的方法:

 
private List list;
  public void add(Object obj) {
  synchronized(list) {
  list.add(obj);
  }
  }
  public void perform( ) {
  Iterator iterator = null;
  synchronized(list) {
  iterator = new CopiedIterator(list.iterator( ));
  }
  while(iterator.hasNext( )) {
  // perform resource or cpu hungry work
  }
  }
重要的是记住,CopiedIterator不是一个克隆,只是一个只读的拷贝,所以它并没有保持原有的全部功能。最重要的是,不能再调用CopiedIterator.remove方法了。CopiedIterator.remove的实现如下:

 
public class CopiedIterator implements Iterator {
  private Iterator iterator = null;
  public CopiedIterator(Iterator itr) {
  LinkedList list = new LinkedList( );
  while(itr.hasNext( )) {
  list.add(itr.next( ));
  }
  this.iterator = list.iterator( );
  }
  public boolean hasNext( ) {
  return this.iterator.hasNext( );
  }
  public void remove( ) {
  throw new UnsupportedOperationException("This is a read-only iterator. 
  ");
  }
  public Object next( ) {
  return this.iterator.next( );
  }
  }
枚举器的只读拷贝将用在同步状态上的时间减少到最小,因此可以增强全局的效率。

ConcurrentModificationException 源码解析

ConcurrentModificationException 源码解析

ConcurrentModificationException 源码解析 博客分类: java
// Iterators

    /**
     * Returns an iterator over the elements in this list in proper
     * sequence. <p>
     *
     * This implementation returns a straightforward implementation of the
     * iterator interface, relying on the backing list''s <tt>size()</tt>,
     * <tt>get(int)</tt>, and <tt>remove(int)</tt> methods.<p>
     *
     * Note that the iterator returned by this method will throw an
     * <tt>UnsupportedOperationException</tt> in response to its
     * <tt>remove</tt> method unless the list''s <tt>remove(int)</tt> method is
     * overridden.<p>
     *
     * This implementation can be made to throw runtime exceptions in the face
     * of concurrent modification, as described in the specification for the
     * (protected) <tt>modCount</tt> field.
     *
     * @return an iterator over the elements in this list in proper sequence.
     * 
     * @see #modCount
     */
    public Iterator<E> iterator() {
	return new Itr();
    }

   

   

private class Itr implements Iterator<E> {
	/**
	 * Index of element to be returned by subsequent call to next.
	 */
	int cursor = 0;

	/**
	 * Index of element returned by most recent call to next or
	 * previous.  Reset to -1 if this element is deleted by a call
	 * to remove.
	 */
	int lastRet = -1;

	/**
	 * The modCount value that the iterator believes that the backing
	 * List should have.  If this expectation is violated, the iterator
	 * has detected concurrent modification.
         *这个modCount值,迭代器相信支持列表应该有。如果这种期望是违反,迭代器已检测到并发改          *。就会报异常
	 */
	int expectedModCount = modCount;

	public boolean hasNext() {
            return cursor != size();
	}

	public E next() {
            checkForComodification();
	    try {
		E next = get(cursor);
		lastRet = cursor++;
		return next;
	    } catch(IndexOutOfBoundsException e) {
		checkForComodification();
		throw new NoSuchElementException();
	    }
	}

 

  

final void checkForComodification() {
	    if (modCount != expectedModCount)
		throw new ConcurrentModificationException();
	}
    }

 

ConcurrentModificationException异常

ConcurrentModificationException异常

我有一个方法test(),其中我试图将两个LinkedHashMap相互比较,并通过删除键/值对(如果在两个LHM中都找到)来修改其中一个映射的内容。运行此方法时,我不断收到ConcurrentModificationException。我知道为什么会收到异常(因为我正在尝试修改正在循环的列表)。我不确定如何进行此操作。到目前为止,我有以下代码:

private void test() {LinkedHashMap<String, BigDecimal>testBene = new LinkedHashMap<String, BigDecimal>();LinkedHashMap<String, BigDecimal>testDly = new LinkedHashMap<String, BigDecimal>();testBene.put("ABCDEFG", BigDecimal.ZERO);testBene.put("BCDEFGH", BigDecimal.ONE);testBene.put("CDEFGHI", BigDecimal.TEN);testDly.put("BCDEFGH", BigDecimal.ONE);testDly.put("Foo", BigDecimal.TEN);testDly.put("Bar", BigDecimal.TEN);for (Entry<String, BigDecimal> beneKeySet : testBene.entrySet()) {    if (testDly.containsKey(beneKeySet.getKey())) {        for (Entry<String, BigDecimal> dlyKeySet : testDly.entrySet()) {            if ((dlyKeySet.getKey().equals(beneKeySet.getKey())) &&                 dlyKeySet.getValue().equals(beneKeySet.getValue())) {                    testBene.remove(dlyKeySet.getKey());            }        }    }}}

答案1

小编典典

您可以使用迭代器:

for (Iterator<Entry<String, BigDecimal>> it = testBene.entrySet().iterator(); it.hasNext();) {    Entry<String, BigDecimal> beneKeySet = it.next();    if (testDly.containsKey(beneKeySet.getKey())) {        for (Entry<String, BigDecimal> dlyKeySet : testDly.entrySet()) {            if ((dlyKeySet.getKey() == beneKeySet.getKey()) && dlyKeySet.getValue() == beneKeySet.getValue()) {                it.remove();            }        }    }}

我们今天的关于子列表抛出ConcurrentModificationException输出列表中的子列表的分享就到这里,谢谢您的阅读,如果想了解更多关于ArrayList什么情况会抛出ConcurrentModificationException、ConcurrentModificationException、ConcurrentModificationException 源码解析、ConcurrentModificationException异常的相关信息,可以在本站进行搜索。

本文标签: