用于生成ConcurrentModificationException的Java示例代码

时间:2016-01-03 20:21:24

标签: java multithreading concurrency

我希望下面的代码抛出一个ConcurrentModificationException,但我得到一个ArrayIndexOutOfBoundsException。

我知道根据下面的javadoc不能保证ConcurrentModificationException,但是我试图重新创建导致 ConcurrentModificationException 的场景,以便更好地理解并发机制错误。

来自ArrayList javadoc

  

失败快速迭代器会尽最大努力抛出ConcurrentModificationException。因此,编写依赖于此异常的程序以确保其正确性是错误的:迭代器的快速失败行为应仅用于检测错误。

public class RaceConditions {

    private static final int NUM_THREADS = 1000;
    private static final int NUM_ELEMENTS = 10000;
    private List<Integer> list = new ArrayList<>();

    public static void main(String... args) {

        for (int i = 0; i < NUM_THREADS; i++) {
            final int fi = i;

            new Thread() {
                @Override
                public void run() {
                    for (int j = 0; j < NUM_ELEMENTS; j++) {
                        list.add(0, fi);
                    }
                }
            }.start();
        }

        System.out.println(list.size());
    }
}

我的问题是我需要在上面的代码中修改什么才能获得保证(或几乎保证)的 ConcurrentModificationException

4 个答案:

答案 0 :(得分:3)

这将始终为您提供ConcurrentModificationException

[None, dict(initial=T.zeros(self.hidden_dim))]

当您尝试在当前迭代它时更改集合时,抛出此异常。

答案 1 :(得分:2)

尽管名称不同,ConcurrentModificationException不仅出现在多线程应用程序中。相反,它通常表示在您迭代或以其他方式与集合交互时修改了集合。作为RuntimeException,它通常表示编程错误。如果您不滥用您正在使用的收藏品,则不应该看到CME。

生成一个的最简单方法是从for-each循环内部调用.remove()。发生这种情况是因为for-each循环正在使用的Iterator跟踪集合中的位置(例如,ArrayList它跟踪当前索引)。如果通过调用.remove()来修改集合,则迭代器的状态不再与集合的状态一致,因此迭代器将通过提升CME 来快速失败 em>它能够检测到不一致。

以下是一个例子:

  1. 构建包含ArrayList
  2. [1, 2, 3, 4]
  3. 致电.iterator()以获取此列表的Iterator。在内部,Iterator将指向索引0
  4. 在迭代器上调用.next(),返回1并将内部指针推进到索引1
  5. 在列表中调用.remove(0),从列表中删除第0个元素1,然后将其余元素向前移动一个。我们的列表现在是[2, 3, 4]
  6. 在迭代器上调用.next()。由于它的内部状态指向索引1,它将返回3,跳过2,这将是一个问题。如果可能,迭代器将检测到这种不一致并失败,而不是默默地继续错误。
  7. java.util中的所有馆藏都会做额外的工作来检测这些不一致性,并在可能的情况下提升CME,而大多数其他热门馆藏(如Guava&#39; s)也会这样做。但是不可能总是检测到这些问题,所以他们只能承诺尽力而为的错误检查,这就是为什么Javadoc必须有些模糊。

答案 2 :(得分:1)

你误解了这个例外。来自ConcurrentModificationException

  

当不允许进行此类修改时,检测到对象的并发修改的方法可能抛出此异常。

     

例如,一个线程通常不允许修改Collection 而另一个线程迭代它

在您的示例中,列表上没有迭代,因此永远不会抛出此异常。

答案 3 :(得分:0)

这应该有助于生成concurrentmodificationexception:通过迭代器访问元素并直接修改列表

List<String> data1 = new ArrayList();
        data1.add("A");
        data1.add("AB");
        data1.add("ABC");
        data1.add("ABCD");

        Iterator itr = data1.iterator();

        while (itr.hasNext()) {
            itr.next();
            System.out.println(itr.next());
            itr.remove();
            data1.add("E");
        }