简体   繁体   English

在多线程程序中使用迭代器时获取并发修改异常

[英]Getting concurrent modification exception while using iterator in multithreaded program

My code is: 我的代码是:

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();
        }
    }
}

I'm getting java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(Unknown Source) at java.util.ArrayList$Itr.next(Unknown Source)... . 在java.util.ArrayList $ Itr.checkForComodification(Unknown Source)处获取了java.util.ConcurrentModificationException

However, 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. 但是,我认为通过使用迭代器,可以避免在修改集合的同时迭代集合的问题。 I didn't have this problem in my non-multithreaded implementation of my program so I'm assuming this has to do with multiple threads doing something with iterator. 我在程序的非多线程实现中没有这个问题,所以我假设这与使用迭代器执行某些操作的多个线程有关。 Does anyone have any ideas? 有人有什么想法吗?

Java's ArrayList isn't thread safe, regardless of whether you use an iterator. Java的ArrayList并不是线程安全的,无论您是否使用迭代器。

From the Javadoc : 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. 如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改列表,则必须在外部进行同步。

... ...

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 此类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时间以任何方式对列表进行结构修改,则除了通过迭代器自己的remove或add方法之外,迭代器都会抛出ConcurrentModificationException

Take a look at this question for a discussion of thread-safe alternatives. 请看一下这个问题 ,以讨论线程安全替代方案。 Basically, you'll need to either use locks (such as synchronized blocks), or a suitable thread-safe list. 基本上,您将需要使用锁(例如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. 我以为通过使用迭代器,可以避免在修改集合的同时迭代集合的问题。

This is true about ListIterator<T> s, not simply Iterator<T> s. 关于ListIterator<T> ,这是正确的,而不仅仅是Iterator<T> In order to avoid ConcurrentModificationException on removal, several things must be true: 为了避免在删除时发生ConcurrentModificationException ,必须满足以下几点:

  • ListIterator<T> must support remove() - this operation is optional ListIterator<T>必须支持remove() -此操作是可选的
  • Your code must remove the item by calling list iterator's remove() - removing directly from the list does not work 您的代码必须通过调用列表迭代器的remove()来删除项目 -直接从列表中删除不起作用
  • There must be no concurrent removals through other iterators - ListIterator<T> takes care of removals through the same iterator object; 不得通过其他迭代器同时进行删除 ListIterator<T>负责通过同一迭代器对象进行删除; they do not help when your code removes items concurrently from different threads. 当您的代码从不同线程中同时删除项目时,它们无济于事。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM