2013-01-05 8 views
3

嗨即時寫一個非常簡單的遊戲。玩家可以使用鼠標移動太空船,每拍攝200毫米新光束。該光束在while(true)循環中移動,當它的y爲0或400(框架邊界)時,我使用break來結束循環(和線程)。每束都有自己的線程。還有在後臺移動的明星。他們每個人都像梁一樣移動並擁有自己的線程。正如你所看到的那樣,經常會添加和從arrayLists中刪除。一切正常,但不時我得到這樣的錯誤:獲取線程和arrayLists相關的錯誤

Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException 
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819) 
    at java.util.ArrayList$Itr.next(ArrayList.java:791) 
    at spacecommander.MainPanel.paintComponent(MainPanel.java:50) 

他們犯規讓比賽中的任何問題,但我怎麼能消除呢?也許我應該使用同步或什麼?

編輯:這裏是代碼

public class MainPanel extends JPanel { 
    private Player player = new Player(100, 100, 3, 3); 
    private Point2D targetPoint = new Point2D.Float(130, 350); //Poczatkowa pozycja statku 
    private ArrayList<Beam> beams = new ArrayList<Beam>(); 
    private InputMap imap = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); 
    private ActionMap amap = getActionMap(); 
    private Random rand = new Random(); 

    public MainPanel() { 
     setPreferredSize(new Dimension(300, 400)); 

     addMouseMotionListener(new MouseMotionHandler()); 

     //Rozpoczynanie watkow 
     Thread t = new Thread(new PlayerMoveRunnable()); 
     t.start(); 
     Thread t2 = new Thread(new PlayerShootRunnable()); 
     t2.start(); 
    } 

    public void paintComponent(Graphics g) { 
     Graphics2D g2 = (Graphics2D)g; 
     g2.setColor(Color.BLACK); 
     g2.fillRect(0, 0, 300, 400); 
     //Rysowanie gracza 
     g2.drawImage(player.getImage(), (int)player.getX(), (int)player.getY(), null); 
     //Rysowanie pociskow 
     for (Beam beam : beams) { 
      g2.drawImage(beam.getImage(), (int)beam.getX(), (int)beam.getY(), null); 
     } 
    } 

    public void makeShortcut(String name, String keys, AbstractAction action) { 
     imap.put(KeyStroke.getKeyStroke(keys), name); 
     amap.put(name, action); 
    } 

    //Watek dziala caly czas bo gracz i tak caly czas sie rusza 
    private class PlayerMoveRunnable implements Runnable { 
     public void run() { 
      try { 
       while (true) { 
        player.moveToPoint(targetPoint); 
        repaint(); 
        Thread.sleep(15); 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    //Takze dziala caly czas. Dodaje nowy pocisk co 200ms 
    private class PlayerShootRunnable implements Runnable { 
     public void run() { 
      try { 
       while (true) { 
        //Wybranie pocisku do wystrzelenia w zaleznosci od mode gracza 
        Thread t; 
        switch (player.getBeamMode()) { 
        case 1: 
         t = new Thread(new BeamMoveRunnable(new Beam1(100, 100, 10, 10, 10))); 
         break; 
        } 
        t.start(); 
        Thread.sleep(200); 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    private class BeamMoveRunnable implements Runnable { 
     private Beam beam; 

     public BeamMoveRunnable(Beam beam) { 
      this.beam = beam; 
     } 

     public void run() { 
      Beam beam = this.beam; 
      beams.add(beam); 
      try { 
       while (true) { 
        if (beam.getY() <= 0) { 
         beams.remove(beam); 
         break; 
        } 
        beam.move(); 
        repaint(); 
        Thread.sleep(20); 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    private class MouseMotionHandler extends MouseAdapter { 
     public void mouseMoved(MouseEvent event) { 
      targetPoint = event.getPoint(); 
     } 
    } 
} 
+0

顯示刪除項我們適當的src,不只是錯誤 – Jayamohan

回答

2

這似乎是一個同步問題,正如您懷疑的那樣。可能在您的繪圖代碼迭代beams -list時,BeamMoveRunnable會同時修改列表(添加或刪除光束),並導致ConcurrentModificationException異常。就我個人而言,我不會使用單獨的線程移動光束,而是一個簡單的循環,首先更新遊戲(一次移動所有光束等),然後重新繪製屏幕。但是,您也可以將訪問權限同步到列表中,以便一次只能有一個線程訪問它。

+0

我會嘗試同步丁,並希望它會解決錯誤:)感謝您的答覆 –

1

當您嘗試添加或從列表中刪除項目,而迭代這通常發生:

for (String s : list) { 
    list.add("abc"); //ConcurrentModificationException 
} 

是很困難的是沒有更具體看到MainPanel類的第50行左右的代碼(參見stacktrace:at spacecommander.MainPanel.paintComponent(MainPanel.java:50))。

編輯

按照你的編輯,一個簡單的變化是使用的CopyOnWriteArrayList是線程安全的,而不是一個ArrayList,握住你的梁對象。

1

由於您正在使用多個線程,不同的線程正試圖修改您的beams arraylist。您可以使用synchronized塊,以避免concurent修改例外如下

循環列表

synchronized (beams) { 
    for (Iterator it = beams.iterator(); it.hashNext();) { 
     Beam beam = (Beam) it.next(); 
     g2.drawImage(beam.getImage(), (int)beam.getX(), (int)beam.getY(), null); 
    } 
} 

添加項目到列表

syncronized (beams) { 
    beams.add(beam); 
} 

從列表

syncronized (beam) { 
    list.remove(beam); 
}