3

Hi im writting a very simple game. Player can use mouse to move spaceship and every 200ms new beam is shoot. This beam is moved in while(true) loop and when its y is 0 or 400 (bounds of frame) i use break to end the loop (and thread). Every beam has its own thread. There are also stars which move in background. Every of them moves like beams and has its own thread. So as you can see there are often add and removes from arrayLists. Everything works but from time to time I get such errors:

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)

They doesnt make any problems in game but how can I eliminate them? Maybe I should use synchronization or something?

EDIT: HERE IS THE CODE

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();
        }
    }
}
1
  • show us the appropriate src, not just the error Commented Jan 5, 2013 at 11:41

3 Answers 3

2

This seems to be a synchronization issue, as you suspected. Probably while your drawing code is iterating the beams-list, a BeamMoveRunnable modifies the list at the same time (either adding or removing a beam), and causes the ConcurrentModificationException. Personally I wouldn't use separate threads to move the beams, but a simple loop which first updates the game (moving all the beams one at a time etc.) and then redraws the screen. However, you can also just synchronize the access to the list so only a single thread can access it at a time.

Sign up to request clarification or add additional context in comments.

1 Comment

I will try synchronizating and hope it will solve errors :) Thanks for reply
1

Since you are using multiple threads different threads are trying to modify your beams arraylist. You can use synchronized block to avoid concurent modification exception as below

Looping the list

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

Adding item to the list

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

removing item from the list

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

Comments

1

This typically happens when you try to add or remove an item from a list while iterating:

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

It is difficult to be more specific without seeing the code that is around line 50 of your MainPanel class (cf. stacktrace: at spacecommander.MainPanel.paintComponent(MainPanel.java:50)).

EDIT

Following your edit, a simple change would be to use a CopyOnWriteArrayList which is thread safe, instead of an ArrayList, to hold your Beam objects.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.