简体   繁体   English

由于未同步的同步方法,导致ConcurrentModicationException

[英]ConcurrentModicationException due to unsynchronized synchronized methods

I have a bunch of Runnable objects that are launched from a base class. 我有一堆从基类启动的Runnable对象。 These objects are iterating through and deleting items in a shared ArrayList at random times. 这些对象在随机时间遍历并删除共享ArrayList中的项目。 I have synchronized both methods but am getting a ConcurrentModicationException . 我已经同步了这两种方法,但是却收到了ConcurrentModicationException I believe its because they are synchronized but are not synchronized on each other . 我相信这是因为它们是同步的,但彼此之间不同步 Is this the case? 是这样吗 If so, which class do I acquire the lock on? 如果是这样,我应该获得哪个类的锁?

Environment Class: 环境等级:

class Environment{

     ArrayList<Critter> critter_array = new ArrayList<Critter>();
     ArrayList<Food> food_array = new ArrayList<Food>();

     Environment(){
         Executor ex = Executors.newCachedThreadPool(); 
         Critter A = new Critter();
         Critter B = new Critter();
         critter_array.add(A);
         critter_array.add(B);
         ex.execute(A); 
         ex.execute(B);
     }

     public synchronized void destroyFood(Food item){
         Iterator<Food> iter = food_array.iterator();
         while(iter.hasNext()){
             Food temp = iter.next();
             food_array.remove(temp);
             break;
         }      
     }

}

Critter class: 小动物班:

class Critter implements Runnable{
     Environment envi;

     Critter(Environment E){
          envi = E;
     }

     @Override
     public void run() {
         //do other stuff
         CritterUtilities.iteratorMethod(this, envi);
     }
}

CritterUtilities class: CritterUtilities类:

class CritterUtilities{

    public static synchronized iteratorMethod(Critter self, Environment envi){
         Iterator<OtherObject> iter = envi.getFood().listIterator();
         while(iter.hasNext()){
             Food temp = iter.next();   /////////Problem is here
             //other stuff that's not related to the prob
        }
    }

}

Stack Trace: 堆栈跟踪:

Exception in thread "pool-1-thread-2" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
at java.util.AbstractList$Itr.next(Unknown Source)
at CritterUtil.getViewableFood(CritterUtil.java:28)
at CritterUtil.getNearestFood(CritterUtil.java:41)
at Critter.hunt(Critter.java:163)
at Critter.run(Critter.java:139)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

The error doesn't necessarily stem multithreading here, but rather the fact that you're removing items from the list while using an iterator: 该错误不一定在此处阻止多线程,而是在使用迭代器时从列表中删除项目的事实:

 public synchronized void destroyFood(Food item){
     Iterator<Food> iter = food_array.iterator();
     while(iter.hasNext()){
         Food temp = iter.next();
         food_array.remove(temp); // <-- this is the problem
         break;
     }      
 }

Instead, use the Iterator.remove() method: 而是使用Iterator.remove()方法:

 public synchronized void destroyFood(Food item){
     Iterator<Food> iter = food_array.iterator();
     while(iter.hasNext()){
         iter.remove(); // <-- this is how you remove elements while iterating
         break;
     }      
 }

On another note, your synchronization is wrong. 另一方面,您的同步错误的。 Each of your synchronized methods is syncing on a different object. 您的每个synchronized方法都在不同的对象上同步。 To get them to all synchronize on the same object it would probably be easiest to just have them all synchronize on the list itself. 为了使它们都在同一个对象上同步,将它们全部同步在列表本身上可能是最简单的。

In addition to the faulty removal spotted by DaoWen, the synchronization is wrong with too. 除了DaoWen发现的错误删除操作之外,同步也是错误的。 iteratorMethod() and destroyFood() do not use the same object for sychronization. iteratorMethod()destroyFood()不会使用相同的对象进行同步。 Currently they use their respective objects for synchronization. 当前,他们使用各自的对象进行同步。 It should be something like this instead: 应该是这样的:

 public void destroyFood(Food item) {
     synchronized (food_array) {
         // ... proceed with the removal
     }
 }

and

public static iteratorMethod(Critter self, Environment envi){
    List<OtherObject> list = envi.getFood();
    synchronized (list) {
        // the rest of iteratorMethod should go here
    }
}

(I'm assuming getFood() returns the food array, so that then the objects would be the same). (我假设getFood()返回food数组,因此对象将相同)。

The same fix should be applied to any other methods modifying, or iterating the the food list. 相同的解决方案应应用于修改或迭代食物清单的任何其他方法。

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

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