2013-08-05 65 views
2

我有一堆從基類啓動的Runnable對象。這些對象隨機遍歷和刪除共享ArrayList中的項目。我已同步這兩種方法,但得到ConcurrentModicationException。我相信它是因爲they are synchronized but are not synchronized on each other。是這樣嗎?如果是這樣,我會獲得哪個課程的鎖定?由於未同步的同步方法導致ConcurrentModicationException

環境類別:

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

} 

小動物類:

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{ 

    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 
     } 
    } 

} 

堆棧跟蹤:

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) 
+0

是的,他們在不同的事情上同步。 – zapl

+0

破壞方法中的「food_list」是什麼? – d0x

+0

@ChristianSchneider我的壞,編輯 – Daniel

回答

4

錯誤並不一定在這裏幹多線程,而是你從列表中同時使用迭代器刪除項目的事實:

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

相反,使用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; 
    }  
} 

另一個說明,您的同步錯誤。您的​​方法中的每一個都在不同的對象上進行同步。爲了讓它們在同一個對象上同步,最簡單的方法是讓它們全部在列表本身上同步。

+0

問題,因爲我以前從未使用過這個類:是否將原始元素(本例中爲'food_array')列表中的元素刪除? – Deactivator2

+1

@ Deactivator2 - 更新了我的答案。該文件稱它將它從_list_中刪除,而不僅僅是_iterator_。 – DaoWen

+1

你不需要'ListIterator'。它比常規的'Iterator'增加的唯一的事情是你可以在兩個方向上迭代。兩者的'remove'都是一樣的。 – zapl

1

除了DaoWen發現的錯誤刪除,同步也是錯誤的。 iteratorMethod()destroyFood()不使用同一個對象進行同步。目前他們使用他們各自的對象進行同步。它應該是這樣,而不是:

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

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

(我假設getFood()返回數組的食物,讓那麼對象將是相同的)。

相同的修補程序應該應用於修改或迭代食物列表的任何其他方法。