You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swing StyleGroupSet并发修改异常问题及解决方法咨询

解决Swing集成GraphStream时的ConcurrentModificationException异常

问题根因

你的代码存在跨线程并发修改Graph集合的问题:

  • Simulator类的start方法里,while循环运行在main线程中,每次调用updateFrame直接修改Graph(添加/删除边)。
  • 你使用的Viewer.ThreadingModel.GRAPH_IN_GUI_THREAD模型,会让GraphStream在AWT事件调度线程(EDT)中执行渲染逻辑,遍历Graph的元素集合。
  • 当main线程修改集合的同时,EDT线程正在遍历它,直接触发了ConcurrentModificationException。

解决方案

所有对Graph的修改操作必须放到**AWT事件调度线程(EDT)**中执行,同时遵循Swing单线程模型规范,推荐两种实现方式:

方式1:用Swing Timer替代while循环

Swing Timer的任务会自动在EDT中执行,完美匹配Swing和GraphStream的线程要求:

修改Simulator类的start方法:

public void start() {
    SwingUtilities.invokeLater(() -> {
        graphFrame = new GraphFrame();
        graphFrame.setVisible(true);
        graphFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    });

    // 用Swing Timer替代while循环,每隔1秒执行一次更新
    Timer timer = new Timer(1000, e -> {
        if (graphFrame != null) {
            graphFrame.updateFrame();
        }
    });
    timer.start();
}

同时修正GraphFrame的updateFrame方法(修复原删除逻辑的索引越界问题):

public void updateFrame(){
    SwingUtilities.invokeLater(() -> {
        addRandomEdge();
        // 先获取所有边的列表,再随机删除其中一条
        if (!graph.getEdgeSet().isEmpty()) {
            List<Edge> edges = new ArrayList<>(graph.getEdgeSet());
            graph.removeEdge(edges.get(rand.nextInt(edges.size())));
        }
        pipeIn.pump();
    });
}

方式2:在修改Graph时强制切换到EDT

如果必须保留while循环,需要把所有Graph修改操作通过SwingUtilities.invokeLater包装:

修改Simulator的while循环部分:

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

    // 把更新操作放到EDT执行
    SwingUtilities.invokeLater(() -> graphFrame.updateFrame());
}

同步修正GraphFrame的updateFrame中的删除逻辑:

public void updateFrame(){
    addRandomEdge();
    if (!graph.getEdgeSet().isEmpty()) {
        List<Edge> edges = new ArrayList<>(graph.getEdgeSet());
        graph.removeEdge(edges.get(rand.nextInt(edges.size())));
    }
    pipeIn.pump();
}

额外注意点

  • 原代码中graph.removeEdge(rand.nextInt(graph.getNodeSet().size()))存在逻辑错误:removeEdge需要传入边的ID或Edge对象,你传入的是节点数量范围内的随机数,大概率找不到对应边,甚至可能抛出异常,必须修正为基于边集合的随机删除逻辑。
  • GraphStream的GRAPH_IN_GUI_THREAD模型要求Graph的所有修改都在EDT中进行,这是避免并发问题的核心前提。

内容的提问来源于stack exchange,提问作者Kfir Ettinger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 20:48:45