2013-01-08 47 views
0

我用Java編寫了一個簡單的遊戲。這裏是主要代碼:獲得併發修改異常。哪裏有問題? (code)

public class MainPanel extends JPanel { 
    private Player player = new Player(100, 100, 3, 3); 
    private Point2D targetPoint = new Point2D.Float(130, 350); //Pos on begin 
    private ArrayList<Beam> beams = new ArrayList<Beam>(); 

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

     addMouseMotionListener(new MouseMotionHandler()); 
     //Add shortcuts 
     makeShortcut("player.BM1", "F1", new SetBeamModeAction(1)); 
     makeShortcut("player.BM2", "F2", new SetBeamModeAction(2)); 

     //Start threads 
     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); 
     //Draw player 
     g2.drawImage(player.getImage(), (int)player.getX(), (int)player.getY(), null); 
     //Draw beams 
     for (Beam beam : beams) { 
      g2.drawImage(beam.getImage(), (int)beam.getX(), (int)beam.getY(), null); 
     } 
    } 

    //Thread running all the time 
    private class PlayerMoveRunnable implements Runnable { 
     public void run() { 
      try { 
       while (true) { 
        player.moveToPoint(targetPoint); 
        repaint(); 
        Thread.sleep(15); 
       } 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

    //Thread working all the time 
    private class PlayerShootRunnable implements Runnable { 
     public void run() { 
      try { 
       while (true) { 
        //Choose which beam to shoot (depends on set mode) 
        Thread t; 
        switch (player.getBeamMode()) { 
         case 1: 
          t = new Thread(new BeamMoveRunnable(new Beam1(player.getX()+18, player.getY(), 0, -15))); 
          break; 
         case 2: 
          t = new Thread(new BeamMoveRunnable(new Beam2(player.getX()+18, player.getY(), 0, -30))); 
          break; 
         default: 
          t = null; 
          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(); 
      } 
     } 
    } 
} 

[它不是整個代碼。我切幾線,可以肯定的arent造成問題]

即時得到這樣的錯誤:

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:53) 
    at javax.swing.JComponent.paint(JComponent.java:1054) 

等等...

如果這就是問題所在?我知道ConcurrentModificationException是什麼意思,但我不知道這裏的問題在哪裏。也許我應該做一些同步。如果是,請顯示其中

+0

順便說一句,你的PlayerShootRunnable永遠循環。每200毫秒,它創建一個新的BeamMoveRunnable線程,它也永遠運行。你每秒創建5個新線程,並且他們都不會退出。 – dashrb

+0

當任何光束變爲0或更大位置時,循環中斷,線程結束。 –

+0

是的,公平點。對不起,我錯過了。仍然看起來像實質線程流失,恕我直言。 – dashrb

回答

0

您正在修改線程BeamMoveRunnable中的arraylist beams(包含此Runnable對象的線程),同時在方法paintComponent中迭代它。這是例外的原因。

1

您正在修改另一個線程中的波束列表,例如BeamMoveRunnable而您正在迭代集合。

爲每個對象創建一個線程非常浪費且難以管理。

我建議你有一個線程定期調用每個光束上的方法來移動。我建議你在繪製時不要添加或移除橫樑,這樣你就不必同步訪問集合。

+0

好的,我會改變它,並製作一個線程,它可以移動每個光束。但我認爲它無論如何不會幫助,因爲即使這樣,有可能線程會循環收集並刪除一個元素,而繪畫方法將嘗試繪製它。那麼如何防止它呢? –

+0

這就是爲什麼我說,不要刪除任何元素。您只能繪製'paintComponent'中可見的元素,而不是將其移除。 –

+0

但不會影響應用程序的性能?或者不會拋出任何異常像堆棧溢出等?新的光束每200ms自動添加一次,所以在幾分鐘的遊戲中會有很多光束。 –

1

在迭代橫樑paintComponent之前,創建集合的副本並使用副本進行迭代。