我希望下面的代码抛出一个ConcurrentModificationException,但我得到一个ArrayIndexOutOfBoundsException。
我知道根据下面的javadoc不能保证ConcurrentModificationException,但是我试图重新创建导致 ConcurrentModificationException 的场景,以便更好地理解并发机制错误。
失败快速迭代器会尽最大努力抛出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 ?
答案 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>它能够检测到不一致。
以下是一个例子:
ArrayList
[1, 2, 3, 4]
.iterator()
以获取此列表的Iterator
。在内部,Iterator
将指向索引0
。.next()
,返回1
并将内部指针推进到索引1
。.remove(0)
,从列表中删除第0个元素1
,然后将其余元素向前移动一个。我们的列表现在是[2, 3, 4]
。.next()
。由于它的内部状态指向索引1
,它将返回3
,跳过2
,这将是一个问题。如果可能,迭代器将检测到这种不一致并失败,而不是默默地继续错误。 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");
}