2012-01-12 125 views
2

我正在創建一個Swing應用程序來製作遊戲。它在屏幕上隨機創建圖像,當它們離開屏幕時,我想刪除它們。請看看代碼片段:暫停一個線程以防止ConcurrentModificationException?

public void checkTrolls(){ //CAUSES EXCEPTION ERROR WHEN SPRITE EXIT SCREEN 
    for(AutomatedSprite a : trolls){ 
     if(a.getX() < 0 - a.getImage().getWidth()) 
      trolls.remove(a); 
     if(a.getY() < 0 - a.getImage().getWidth()) 
      trolls.remove(a); 
     if(a.getX() > 800) 
      trolls.remove(a); 
     if(a.getY() > 600) 
      trolls.remove(a); 
    } 
} 

@Override 
public void run() { 
    long beforeTime, timeDiff, sleep; 

    beforeTime = System.currentTimeMillis(); 

    while(true){ 
     dodger.update(); //update sprite 
     if(trolls.size() != 6){ 
      trolls.add(new AutomatedSprite("images/troll_face.png")); 
     } 
     for(Sprite troll : trolls){ 
      troll.update();   //UPDATES MY SPRITES 
     } 
     checkTrolls();    //CHECKS TROLLS EXITING THE SCREEN 
     repaint(); 

     for(Sprite troll : trolls){ 
      System.out.println("X: " + troll.getX()); 
      System.out.println("Y: " + troll.getY()); 
     } 

     timeDiff = System.currentTimeMillis() - beforeTime; 
     sleep = timeDiff - DELAY; 

     if(sleep < 0) 
      sleep = 5; 

     try { 
      Thread.sleep(sleep); 
     } catch (InterruptedException e) { e.printStackTrace(); } 

     beforeTime = System.currentTimeMillis(); 
    } 
} 

巨魔是AutomatedSprites的載體,當他們離開屏幕,我得到一個ConcurrentModificationException的,顯然我無法從我的矢量刪除實例。

因此,似乎我無法從線程中刪除任何東西,而線程正在更新我所有的精靈,有沒有辦法暫停我的線程,所以我可以刪除精靈?

P.S:這裏是在情況下,整個班級我錯過了一些東西:Pastebin

+1

使用'synchronized'方法來操縱矢量。 – 2012-01-12 02:30:29

回答

5

在遍歷它不能從集合中刪除,這是一個單線程的環境以及多線程一個真實的。 syncrhonized仍然會導致Thread.sleep問題。使用和迭代器並以這種方式移除。

public void checkTrolls(){ 
    for(Iterator<AutomatedSprite> itr = trolls.iterator(); itr.hasNext();){ 
     AutomatedSpring nextElemnt = itr.next(); 
     if(youShouldRemoveTheSprite){ 
      itr.remove(); 
     } 
    } 
} 

所以在這裏你使用你的巨魔集合提供的迭代器。並且您要求Iterator安全地從集合中刪除對象。

現在,如果你執行checkTrolls與多個線程,那麼你將需要同步。你可以是這樣做的

public synchronized void checkTrolls(){ ... 

編輯根據你最近評論/鏈接。

這不是你將Iterator.next()分配給一個變量,而是你多次調用iterator.next()。每次調用next()時,您都將迭代器移動到List的下一個元素。因此,在一次循環迭代結束時,您將迭代器移動到列表中的第6個元素。如果你索引它,而不是它看起來像:

for(Iterator<AutomatedSprite> itr = trolls.iterator(); itr.hasNext();){ 
     if(trolls.get(0).getX() < 0 - trolls.get(1).getImage().getWidth() ||  
         trolls.get(2).getY() < 0 - trolls.get(3).getImage().getWidth() || 
         trolls.get(4).getX() > 800 || 
         trolls.get(5).getY() > 600){ 
       trolls.remove(trolls.get(5)); 
     } 

請注意這個例子:索引在0,1,2,3,4 ......只是爲了示範,在實踐中這將是我= 0;開始for循環trolls.get(i ++)。getX(),trolls.get(i ++)。getY()等等。如果你的列表是10,000,你最終會得到一個NoSuchElementException

因此,例如,如果你只有3個巨魔,一旦你到達第四個itr.next(),你會得到一個NoSuchElementException。因此,您需要將next()元素存儲在變量中,並對該變量進行處理,以便itr.hasNext();正確返回並且itr.remove()也能正常工作。

+0

我有一個while循環遍歷checkTrolls()方法中的Vector,但現在我的遊戲甚至不會啓動,因爲它立即得到異常。 我是否必須遍歷所有其他的巨魔實例?如果沒有,那麼我一定會有另一個問題。 – mastrgamr 2012-01-12 03:25:32

+0

如果我用for循環做到這一點,我得到一個NoSuchElementException:/ – mastrgamr 2012-01-12 03:39:27

+0

看看我的編輯你應該做什麼 – 2012-01-12 03:49:06

0

已經運行方法內你的代碼​​塊。同步將確保一次只有一個線程執行您的代碼。

run(){ 
synchronized(this){ 
....your code. 
}} 

您也可以使run()同步。

0

一個簡單而有些天真的解決方案將太簡單地在trolls集合上同步。如果您這樣做,請確保在Animator線程中使用yield以使您的checkTrolls函數有機會進行處理和清理。

0

我認爲這個問題可能是在'checkTrolls'中,你試圖修改一個你正在迭代的矢量。

2

checkTrolls()當您迭代它時,您將從Vector中刪除元素。這將導致ConcurrentModificationException

從Vector的javadoc

的迭代器此類的迭代器返回和的ListIterator 方法是快速失敗的:如果矢量結構在任何 一次創建迭代器後修改,除了通過 迭代器自己的remove或add方法以外,迭代器將拋出一個 ConcurrentModificationException異常。

幾個選擇:

創建元素的列表刪除並充分迭代後刪除它們。

使用一個線程安全的List實現如CopyOnWriteArrayList

+0

我不確定線程​​安全是什麼,我仍然在學習線程是什麼以及如何使用它們。這是一個小遊戲,但是如果我製作的是較大的遊戲或應用程序,使用線程安全集合會影響程序的性能? – mastrgamr 2012-01-12 02:50:58

+0

'CopyOnWriteArrayList'在你的情況下可能太貴了。我懷疑最好通過在迭代它時不從列表中移除元素來解決這個問題。 – 2012-01-12 03:00:10