【问题标题】:Remove List from Vector getting java.util.ConcurrentModificationException从获取 java.util.ConcurrentModificationException 的 Vector 中删除列表
【发布时间】:2012-05-08 19:24:39
【问题描述】:

我试图从如下向量中删除列表。

public class StringVectorTest {

private final List<String> stringVector = new Vector<String>();

@Test
public void listRemoveTest(){

    List<String> list = stringVector.subList(0, 2);

    stringVector.removeAll(list);

    Assert.assertEquals(stringVector.size(), 3);
}

@Before
public void fillList(){
    stringVector.add("ABC");
    stringVector.add("DEF");
    stringVector.add("GEH");
    stringVector.add("IJK");
    stringVector.add("LMN");
}

}

当我运行测试时,我收到以下错误

java.util.ConcurrentModificationException
at java.util.SubList.checkForComodification(AbstractList.java:752)
at java.util.SubList.listIterator(AbstractList.java:682)
at java.util.AbstractList.listIterator(AbstractList.java:284)
at java.util.SubList.iterator(AbstractList.java:678)
at java.util.AbstractCollection.contains(AbstractCollection.java:82)
at java.util.Collections$SynchronizedCollection.contains(Collections.java:1563)
at java.util.AbstractCollection.removeAll(AbstractCollection.java:336)
at java.util.Vector.removeAll(Vector.java:853)

我知道我必须使用Iterator 来克服这个ConcurrentModificationException 任何人都可以让我知道我应该如何以有效的方式/最佳实践使用它吗?

提前致谢。

【问题讨论】:

    标签: java collections iterator concurrentmodification


    【解决方案1】:

    按如下方式进行:

    public void listRemoveTest() {
        stringVector.subList(0, 2).clear();
        Assert.assertEquals(stringVector.size(), 3);
    }
    

    【讨论】:

      【解决方案2】:

      来自ConcurrentModificationException的javadoc:

      当这种修改是不允许的时,检测到对象的并发修改的方法可能会抛出此异常。 例如,通常不允许一个线程在另一个线程对其进行迭代时修改 Collection。一般来说,在这些情况下,迭代的结果是不确定的。如果检测到此行为,某些迭代器实现(包括 JRE 提供的所有通用集合实现的那些)可能会选择抛出此异常。这样做的迭代器被称为fail-fast iterators,因为它们快速而干净地失败,而不是在未来不确定的时间冒着任意、非确定性行为的风险。

      请注意,此异常并不总是表示对象已被不同的线程同时修改。如果单个线程发出一系列违反对象约定的方法调用,则该对象可能会抛出此异常。例如,如果线程在使用 fail-fast 迭代器迭代集合时直接修改集合,则迭代器将抛出此异常。

      后者正是您正在做的事情(请参阅您发布的堆栈跟踪)。由于subList 方法返回列表的视图,因此该方法返回的列表由您的stringVector 支持,因此返回列表中的非结构性更改会反映在stringVector 和反之亦然。

      所以你应该使用这个“视图”来删除元素:

      @Test
      public void listRemoveTestClearingSubList(){
          stringVector.subList(0, 2).clear();    
          Assert.assertEquals(stringVector.size(), 3);
      }
      

      因为使用迭代器有点棘手和丑陋:

      @Test
      public void listRemoveTestClearingWithIterator(){
          Iterator<String> it = stringVector.iterator();
          for (int i = 0; i < 2 && it.hasNext(); i++) {
              it.next();
              it.remove();
          }
      
          Assert.assertEquals(stringVector.size(), 3);
      }   
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-31
        • 2014-05-24
        • 2019-09-06
        • 2013-05-26
        • 2013-08-26
        • 2021-03-01
        • 2014-01-25
        • 2015-09-23
        相关资源
        最近更新 更多