在多线程程序中使用迭代器时出现并发修改异常
Getting concurrent modification exception while using iterator in multithreaded program
我的代码是:
class Processor implements Runnable {
private int id;
private Integer interaction;
private Set<Integer> subset;
private volatile static AtomicBoolean notRemoved = new AtomicBoolean(true);
public Object<E> dcp;
public Iterator<Integer> iterator;
public Processor(int id, Integer interaction, Set<Integer> subset, Object<E> dcp, Iterator<Integer> iterator) {
this.id = id;
this.interaction = interaction;
this.subset= subset;
this.dcp = dcp;
this.iterator = iterator;
}
public void run() {
while (Processor.notRemoved.get()){
System.out.println("Starting: " + this.subset);
if (this.dcp.PA.contains(this.interaction)){
this.subset.add(this.interaction);
this.dcp.increaseScore(this.subset);
if (!this.subset.contains(this.interaction) && Processor.notRemoved.get()){
Processor.notRemoved.set(false);
iterator.remove();
}
}
System.out.println("Completed: " + this.id);
}
}
}
public class ConcurrentApp {
public void multiThreadProgram (Object<E> dcp, int threads) {
ExecutorService executor = Executors.newFixedThreadPool(threads);
int i =1;
while ((dcp.PA.size() > i) && (i <= dcp.R)){
for (Iterator<Integer> iterator = dcp.PA.iterator(); iterator.hasNext();){
Integer interaction = iterator.next();
ArrayList<Integer> removed = new ArrayList<Integer>(dcp.PA);
removed.remove(interaction);
ArrayList<Set<Integer>> subsets = dcp.getSubsets(removed, i);
for (int j = 0; j< subsets.size(); j++){
try {
executor.submit(new Processor(j, interaction, subsets.get(j), dcp, iterator));
} catch (RejectedExecutionException e){
System.out.println("Task was rejected");
}
}
}
System.out.println("All tasks completed");
i++;
}
executor.shutdown();
System.out.println("All tasks submitted");
try {
executor.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我在 java.util.ArrayList$Itr.checkForComodification(未知来源)和 java.util.ArrayList$Itr.next(未知来源)获得 java.util.ConcurrentModificationException )...。
但是,我认为通过使用迭代器,我可以避免在修改我的集合的同时迭代我的集合的问题。我在我的程序的非多线程实现中没有这个问题,所以我假设这与多个线程用迭代器做某事有关。有人有什么想法吗?
Java 的 ArrayList 不是线程安全的,无论您是否使用迭代器。
来自Javadoc:
If multiple threads access an ArrayList instance concurrently, and at
least one of the threads modifies the list structurally, it must be
synchronized externally.
...
The iterators returned by this class's iterator and listIterator
methods are fail-fast: if the list is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove or add methods, the iterator will throw a
ConcurrentModificationException
查看此 question 以了解线程安全替代方案的讨论。基本上,您需要使用锁(例如 synchronized
块)或合适的线程安全列表。
I thought that by using the iterator, I could avoid this problem of iterating over my collection while modifying my collection at the same time.
ListIterator<T>
s 是这样,而不仅仅是 Iterator<T>
s。为了避免 ConcurrentModificationException
删除,必须满足以下几点:
ListIterator<T>
必须支持 remove()
- 这个操作是可选的
- 您的代码必须通过调用列表迭代器的
remove()
来删除项目 - 直接从列表中删除是行不通的
- 不能通过其他迭代器进行并发移除 -
ListIterator<T>
负责通过同一个迭代器对象进行移除;当您的代码从不同线程同时删除项目时,它们无济于事。
我的代码是:
class Processor implements Runnable {
private int id;
private Integer interaction;
private Set<Integer> subset;
private volatile static AtomicBoolean notRemoved = new AtomicBoolean(true);
public Object<E> dcp;
public Iterator<Integer> iterator;
public Processor(int id, Integer interaction, Set<Integer> subset, Object<E> dcp, Iterator<Integer> iterator) {
this.id = id;
this.interaction = interaction;
this.subset= subset;
this.dcp = dcp;
this.iterator = iterator;
}
public void run() {
while (Processor.notRemoved.get()){
System.out.println("Starting: " + this.subset);
if (this.dcp.PA.contains(this.interaction)){
this.subset.add(this.interaction);
this.dcp.increaseScore(this.subset);
if (!this.subset.contains(this.interaction) && Processor.notRemoved.get()){
Processor.notRemoved.set(false);
iterator.remove();
}
}
System.out.println("Completed: " + this.id);
}
}
}
public class ConcurrentApp {
public void multiThreadProgram (Object<E> dcp, int threads) {
ExecutorService executor = Executors.newFixedThreadPool(threads);
int i =1;
while ((dcp.PA.size() > i) && (i <= dcp.R)){
for (Iterator<Integer> iterator = dcp.PA.iterator(); iterator.hasNext();){
Integer interaction = iterator.next();
ArrayList<Integer> removed = new ArrayList<Integer>(dcp.PA);
removed.remove(interaction);
ArrayList<Set<Integer>> subsets = dcp.getSubsets(removed, i);
for (int j = 0; j< subsets.size(); j++){
try {
executor.submit(new Processor(j, interaction, subsets.get(j), dcp, iterator));
} catch (RejectedExecutionException e){
System.out.println("Task was rejected");
}
}
}
System.out.println("All tasks completed");
i++;
}
executor.shutdown();
System.out.println("All tasks submitted");
try {
executor.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
我在 java.util.ArrayList$Itr.checkForComodification(未知来源)和 java.util.ArrayList$Itr.next(未知来源)获得 java.util.ConcurrentModificationException )...。
但是,我认为通过使用迭代器,我可以避免在修改我的集合的同时迭代我的集合的问题。我在我的程序的非多线程实现中没有这个问题,所以我假设这与多个线程用迭代器做某事有关。有人有什么想法吗?
Java 的 ArrayList 不是线程安全的,无论您是否使用迭代器。
来自Javadoc:
If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally.
...
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException
查看此 question 以了解线程安全替代方案的讨论。基本上,您需要使用锁(例如 synchronized
块)或合适的线程安全列表。
I thought that by using the iterator, I could avoid this problem of iterating over my collection while modifying my collection at the same time.
ListIterator<T>
s 是这样,而不仅仅是 Iterator<T>
s。为了避免 ConcurrentModificationException
删除,必须满足以下几点:
ListIterator<T>
必须支持remove()
- 这个操作是可选的- 您的代码必须通过调用列表迭代器的
remove()
来删除项目 - 直接从列表中删除是行不通的 - 不能通过其他迭代器进行并发移除 -
ListIterator<T>
负责通过同一个迭代器对象进行移除;当您的代码从不同线程同时删除项目时,它们无济于事。