CopyOnWriteArrayList(cowal)
CopyOnWriteArrayList(cowal)
我从一些教程中理解了这个概念,只要我知道一个线程何时迭代列表,其他线程就可以修改基础列表,我们不会得到 ConcurrentModificationException(CME) 但在 ArrayList 的情况下我们会得到 CME .
但在下面的程序中只有一个线程(主线程),但我仍然收到 CME ..为什么?
是因为迭代器吗?
如果我用 COWAL 替换 AL 而不是我没有得到任何异常,但我也没有元素 "D".. 为什么?
AL<String> l=new AL<>();
l.add("a");
l.add("b");
l.add("c");
Iterator<String> itr=l.iterator();
l.add("d");
while(itr.hasNext())
{
String s=itr.next();
Sop(s);
}
错误是因为行
l.add("d");
您正在创建迭代器后修改列表结构(添加或删除元素)。
当你打电话时
itr.next();
它在内部检查列表中的任何结构更改(ArrayList 中的添加或删除),它发现添加了一个元素,因此数组列表的大小发生了变化。这就是您得到该异常的原因。
如果您在创建迭代器之前或在使用迭代器之后添加该元素,您将不会收到此错误..
下面是ArrayList中next()的代码Class;
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
......
return (E) elementData[lastRet = i];
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
你得到 ConcurrentModificationException
因为 ArrayList
的迭代器是 fail-fast 设计的。这意味着一旦创建了迭代器,如果ArrayList
被修改(添加或删除元素),它将抛出ConcurrentModificationException
.
如果检查异常日志语句,它被itr.next()
方法抛出在第String s=itr.next();
行,因为迭代器的next()
方法通过调用checkForComodification()
方法检查修改ArrayList
的大小使用 modCount
变量,它在从列表创建迭代器时复制该变量。
现在让我们谈谈 CopyOnWriteArrayList
你没有得到这个异常的地方是因为 CopyOnWriteArrayList
是 [=13= 的 线程安全变量 ] 其中所有可变操作如添加、删除、设置都是通过将内部数组复制到新数组并用新创建的数组替换旧数组来实现的。
因此,当您从列表中获取迭代器时,它包含数组的引用,而当您向列表中添加元素时,列表将拥有全新的数组。并且迭代器仍然指向旧数组。
您可能已经注意到,通过语句 l.add("d");
新添加的元素并未打印在控制台上。但是如果你打印整个列表,它就在那里。
这是您的示例代码 CopyOnWriteArrayList
:
List<String> l = new CopyOnWriteArrayList<>();
l.add("a");
l.add("b");
l.add("c");
Iterator<String> itr = l.iterator();
l.add("d");
while (itr.hasNext()) {
String s = itr.next();
System.out.println(s);
}
System.out.println(l);
产品的输出是:
a
b
c
[a, b, c, d]
希望这对您有所帮助。
享受 :)
我从一些教程中理解了这个概念,只要我知道一个线程何时迭代列表,其他线程就可以修改基础列表,我们不会得到 ConcurrentModificationException(CME) 但在 ArrayList 的情况下我们会得到 CME .
但在下面的程序中只有一个线程(主线程),但我仍然收到 CME ..为什么?
是因为迭代器吗?
如果我用 COWAL 替换 AL 而不是我没有得到任何异常,但我也没有元素 "D".. 为什么?
AL<String> l=new AL<>();
l.add("a");
l.add("b");
l.add("c");
Iterator<String> itr=l.iterator();
l.add("d");
while(itr.hasNext())
{
String s=itr.next();
Sop(s);
}
错误是因为行
l.add("d");
您正在创建迭代器后修改列表结构(添加或删除元素)。
当你打电话时
itr.next();
它在内部检查列表中的任何结构更改(ArrayList 中的添加或删除),它发现添加了一个元素,因此数组列表的大小发生了变化。这就是您得到该异常的原因。
如果您在创建迭代器之前或在使用迭代器之后添加该元素,您将不会收到此错误..
下面是ArrayList中next()的代码Class;
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
......
return (E) elementData[lastRet = i];
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
你得到 ConcurrentModificationException
因为 ArrayList
的迭代器是 fail-fast 设计的。这意味着一旦创建了迭代器,如果ArrayList
被修改(添加或删除元素),它将抛出ConcurrentModificationException
.
如果检查异常日志语句,它被itr.next()
方法抛出在第String s=itr.next();
行,因为迭代器的next()
方法通过调用checkForComodification()
方法检查修改ArrayList
的大小使用 modCount
变量,它在从列表创建迭代器时复制该变量。
现在让我们谈谈 CopyOnWriteArrayList
你没有得到这个异常的地方是因为 CopyOnWriteArrayList
是 [=13= 的 线程安全变量 ] 其中所有可变操作如添加、删除、设置都是通过将内部数组复制到新数组并用新创建的数组替换旧数组来实现的。
因此,当您从列表中获取迭代器时,它包含数组的引用,而当您向列表中添加元素时,列表将拥有全新的数组。并且迭代器仍然指向旧数组。
您可能已经注意到,通过语句 l.add("d");
新添加的元素并未打印在控制台上。但是如果你打印整个列表,它就在那里。
这是您的示例代码 CopyOnWriteArrayList
:
List<String> l = new CopyOnWriteArrayList<>();
l.add("a");
l.add("b");
l.add("c");
Iterator<String> itr = l.iterator();
l.add("d");
while (itr.hasNext()) {
String s = itr.next();
System.out.println(s);
}
System.out.println(l);
产品的输出是:
a
b
c
[a, b, c, d]
希望这对您有所帮助。 享受 :)