使用ExecutorService时出现java.util.ConcurrentModificationException

时间:2015-05-06 11:10:43

标签: java future executorservice

我正在研究一些我正在使用Observer设计模式的项目。 主题类是:

public class Subject {
    private List<Observer> observers = new ArrayList<Observer>();
    private int state;
    public void setState(int state) {
          this.state = state;
          notifyAllObservers();
    }
    public void attach(Observer observer){
          observers.add(observer);      
    }
    public void notifyAllObservers(){
          for (Observer observer : observers) {
             observer.update();
           }
   }
   public void deattach(Observer observer) {
         observers.remove(observer);
   }
}

观察者界面是:

public abstract class Observer implements Runnable{
    protected Subject subject;
    public abstract void update();
    public abstract void process();
}

名为HexObserver的Observer之一是:

public class HexaObserver extends Observer {

    private ExecutorService threadpool = Executors.newFixedThreadPool(10);

    public HexaObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println("Hex String: "
                + Integer.toHexString(subject.getState()));
        Future future = threadpool.submit(new HexaObserver(subject));

    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        System.out.println("In run :D :D :D");

    }

    @Override
        public void process() {
            // TODO 
        }
}

测试它的类是:

public class Demo {
    public static void main(String[] args) {
        Subject subject = new Subject();
        HexaObserver hob = new HexaObserver(subject);
        System.out.println("First state change: 15");
        subject.setState(15);
    }
}

当我尝试运行此操作时,会出现一些错误:

First state change: 15
Hex String: f
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
    at java.util.ArrayList$Itr.next(ArrayList.java:831)
    at Observer.Subject.notifyAllObservers(Subject.java:23)
    at Observer.Subject.setState(Subject.java:15)
    at Observer.Demo.main(Demo.java:12)
In run :D :D :D

当我们尝试在不允许的情况下同时修改某些Object时,我没有理解为什么我收到此错误,因为ConcurrentModificationException被抛出。

我错过了什么吗?

2 个答案:

答案 0 :(得分:0)

同时发生了两件事:你正在迭代observers并向observers添加一个元素。这会导致您ConcurrentModificationException

一般来说,你可以做两件事:

  • 使用同步集合
  • 线程安全地复制集合并迭代副本
  • 手动将observerssynchronized阻止的所有访问权限同步:

public void attach(Observer observer){
      synchronized(observers){ 
          observers.add(observer);      
      }
}
public void notifyAllObservers(){
      synchronized(observers){ 
          for (Observer observer : observers) {
             observer.update();
          }
      }
}
public void deattach(Observer observer) {
      synchronized(observers){ 
           observers.remove(observer);
      }
}
  • 您还可以将整个方法标记为synchronized,但随后它们将在Subject的实例上进行同步,而不是在集合实例上进行同步。

但是,在您的情况下,问题与update()的问题有关 您确定HexaObserver的{​​{1}}应该创建新的update吗?因为您要将同一类的新实例添加到已包含该实例的集合中。

答案 1 :(得分:0)

ConcurrentModificationException通常是您在Iterator上使用Collection的标志,并且在迭代时,您还修改了基础Collection(请记住,foreach-expression是实际上是使用Iterator)的快捷方式。解决这个问题的唯一方法是迭代原始集合的副本。如果您处于多线程环境中,还需要确保以线程安全的方式完成集合的副本。

所以你可以举例:

public class Subject {
    private List<Observer> observers = new Vector<Observer>();
    private int state;
    public void setState(int state) {
          this.state = state;
          notifyAllObservers();
    }
    public void attach(Observer observer){
          observers.add(observer);      
    }
    public void notifyAllObservers(){
          for (Observer observer : ((List<Observer)observers.clone())) {
             observer.update();
           }
   }
   public void deattach(Observer observer) {
         observers.remove(observer);
   }
}