这里有两个线程在同一个arraylist上工作,一个线程读取元素,另一个线程删除特定的元素。我希望这个能扔出去 ConcurrentModificationException
. 但它不扔为什么?
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
public class IteratorStudies {
public static final ArrayList<String> arr ;
static{
arr = new ArrayList<>();
for(int i=0;i<100;i++) {
arr.add("someCommonValue");
}
arr.add("someSpecialValue");
}
private static Integer initialValue = 4;
public static void main(String x[]) {
Thread t1 = new Thread(){
@Override
public void start(){
Iterator<String> arrIter = arr.iterator();
while(arrIter.hasNext()){
try {
String str = arrIter.next();
System.out.println("value :" + str);
}catch(ConcurrentModificationException e){
e.printStackTrace();
}
}
System.out.println("t1 complete:"+arr);
}
};
Thread t2 = new Thread(){
@Override
public void start(){
Iterator<String> arrIter = arr.iterator();
while(arrIter.hasNext()){
String str = arrIter.next();
if(str.equals("someSpecialValue")){
arrIter.remove();
}
}
System.out.println("t2 complete:"+arr);
}
};
t2.start();
t1.start();
}
}
2条答案
按热度按时间snz8szmq1#
您已覆盖
start
两个线程示例的方法,而不是run
,并且这些方法在主执行线程内完成,因此,不会同时执行线程,也不会ConcurrentModificationThreadException
能在这里发生。xkftehaa2#
你犯了两个比较常见的错误。
concurrentmodificationexception与并发无关
你可能会认为,鉴于这个名字,comodex是关于并发性的。不是的。在中,您不需要线程来获取它。在这里,这个琐碎的代码将抛出它:
这是因为Ecomodex是由迭代器抛出的,只是表示发生了这种情况:
有人做了迭代器。
有人以某种方式更改了列表(而不是通过迭代器的.remove()方法)
有人在#1中生成的迭代器上运行任何相关方法
因此,在上面的例子中,foreach循环隐式地生成一个迭代器(#1),然后
list.remove
方法被调用(#2),然后通过再次命中foreach循环,我们调用该迭代器上的相关方法(.hasNext()
),然后,瞧,comodex出现了。事实上,多线程是不太可能的:毕竟,您应该假设,如果您与来自多个线程的某个对象进行交互,那么它将被破坏,因为该行为是未指定的,因此,您有一个bug,更糟糕的是,一个很难测试的bug。如果您在迭代时从另一个线程修改了一个普通的jane arraylist,就不能保证有一个comodex。你会得到的。你可能不会。电脑可能会从table上走下来,在百老汇碰碰运气。”“不特定的行为”是一个很好的表达方式:“不要,说真的。它会一直伤害你,因为你不能测试它;这将在你开发它的整个过程中都很好地工作,而且当你把这个重要的演示给大的wig客户时,它将以令人尴尬的方式在你身上失败。
从多个线程与一个对象进行交互的方法非常小心:检查特定对象的文档,明确说明发生了什么(即使用来自
java.util.concurrent
专门设计了“从多个线程与之交互”用例的包,如果没有,则使用锁定。这些都是很棘手的事情,所以在java中执行多线程的通常方法是首先不要共享状态。尽可能地隔离、反转控制,并使用具有内置事务内部函数的消息传递策略,例如消息队列(rabbitmq和friends)和数据库(具有事务)。如何使用线程
你覆盖了
run()
方法,然后通过调用start
方法。或者更好的是,不要重写run,在创建线程示例时传递一个可运行的示例。你就是这么用线的。您没有-您重写了start,这意味着启动这些线程根本不会生成一个新线程,它只是在您的线程中运行负载。这就解释了你的具体情况,但是你试图做的(通过弄乱另一个线程的列表来见证comodex)也不会得到一个comodex——它会得到你未指定的行为,这意味着任何事情都会发生。