0

I'm using Swing gui with my project with GraphStream's graph in it (not sure if it is relevant), and I keep getting ConcurrentModificationException exception from Swing's StyleGroupSet class.

How can I avoid it?

this is the exception's stackTrace:

Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
    at java.base/java.util.TreeMap$PrivateEntryIterator.nextEntry(TreeMap.java:1486)
    at java.base/java.util.TreeMap$KeyIterator.next(TreeMap.java:1540)
    at org.graphstream.ui.graphicGraph.StyleGroupSet$ElementIterator.next(StyleGroupSet.java:1427)
    at org.graphstream.ui.graphicGraph.StyleGroupSet$ElementIterator.next(StyleGroupSet.java:1411)
    at org.graphstream.ui.graphicGraph.GraphicGraph.computeBounds(GraphicGraph.java:359)
    at org.graphstream.ui.view.Viewer.computeGraphMetrics(Viewer.java:569)
    at org.graphstream.ui.view.Viewer.actionPerformed(Viewer.java:545)
    at java.desktop/javax.swing.Timer.fireActionPerformed(Timer.java:311)
    at java.desktop/javax.swing.Timer$DoPostEvent.run(Timer.java:243)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

By popular demand, Here is My minimized code:

package _IgnoreThatSh1t;

import app.view.frames.SimulatorFrame;

import javax.swing.*;
import java.awt.*;

public class Simulator{
    GraphFrame graphFrame;


    public void start() {
        graphFrame = new GraphFrame();
        graphFrame.setVisible(true);
        graphFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        graphFrame.show();

        while(true){
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            graphFrame.updateFrame();
        }
    }

    public static void main(String[] args) {
        Simulator simulator = new Simulator();
        simulator.start();
    }
}

And the JFrame:


public class GraphFrame extends JFrame {
    private ViewerPipe pipeIn;
    private JPanel graphPanel;
    private Graph graph;
    private Random rand = new Random();

    public GraphFrame(){
        JPanel p = new JPanel();
        JLabel l = new JLabel("my graph!");

        graph = new MultiGraph("my graph");
        System.setProperty("org.graphstream.ui.renderer", "org.graphstream.ui.j2dviewer.J2DGraphRenderer");
        Viewer viewer = new Viewer(graph, Viewer.ThreadingModel.GRAPH_IN_GUI_THREAD);
        graphPanel = viewer.addDefaultView(false);
        pipeIn = viewer.newViewerPipe();
        initGraph();

        p.add(l);
        p.add(graphPanel);
        this.add(graphPanel);

        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        setBounds(100, 100, (int) dim.getWidth(), (int) dim.getHeight());
        setLocationRelativeTo(null);
    }

    private void initGraph(){

        for (int i = 0; i < 1000; i++) {
            graph.addNode(i+"");
        }


        for (int i = 0; i < 500; i++) {
            addRandomEdge();
        }
    }

    private void addRandomEdge(){
        int src = rand.nextInt(graph.getNodeSet().size());
        int dst = rand.nextInt(graph.getNodeSet().size());

        if(src != dst){
            graph.addEdge(src+"-"+dst, src +"", dst +"");
        }
    }

    public void updateFrame(){
        addRandomEdge();
        graph.removeEdge(rand.nextInt(graph.getNodeSet().size()));
        pipeIn.pump();
    }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
Kfir Ettinger
  • 584
  • 4
  • 13
  • 1
    Based on your stack trace, I would say, yes, GraphStream is most likely involve. How? I'm not sure. Are you making sure that all Swing-related calls are being made on the Swing event thread, the EDT? Does the error occur every time you try to run the code? Or is it intermittent? Can you minimize your code to the smallest code that can reproduce this error? – Hovercraft Full Of Eels Aug 16 '22 at 19:59
  • @HovercraftFullOfEels thanks for the feedback, I added some code. And the error occurs almost every time. – Kfir Ettinger Aug 16 '22 at 21:03
  • Your code is at high risk of severe Swing threading issues. I would 1) make sure that all Swing GUI's, including the GraphFrame objects are created on the Swing event thread via `SwingUtilities.invokeLater(() -> {...});, 2) that you get rid of the while loop and Thread sleep, and 3) instead use a Swing Timer to make repeated Swing calls with delay. – Hovercraft Full Of Eels Aug 16 '22 at 21:11
  • Or use a SwingWorker if anything in `updateFrame` takes time to complete, especially `pump()`. No idea what that does. – Hovercraft Full Of Eels Aug 16 '22 at 21:12
  • 1
    For better help, create and post a valid [mre] if at all possible. – Hovercraft Full Of Eels Aug 16 '22 at 21:19
  • @HovercraftFullOfEels thanks! the "minimal reproducible example" tutorial was very helpful for a newbie like me. is that better? – Kfir Ettinger Aug 16 '22 at 22:43
  • @HovercraftFullOfEels and the `pipeIn.pump();` updates the `GraphStream`s graph. – Kfir Ettinger Aug 16 '22 at 22:45
  • Refer to [How to Use Swing Timers](https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html) and [Concurrency in Swing](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html) – Abra Aug 17 '22 at 04:45

0 Answers0