Java swingworker中的并发修改异常

Java swingworker中的并发修改异常,java,swingworker,concurrentmodification,Java,Swingworker,Concurrentmodification,我创建了一个程序来读取串行端口,绘制数据并显示值。我使用SwingWorker来收集、检查和绘制值,同时允许用户停止GUI中的数据收集。我相信当我试图绘制值并显示精确值时,我收到了修改异常 下面是doInBackground()的简化版本。我删除的行基本上是检查和比较读取的值 protected Integer doInBackground() while (true && !isCancelled()) { value = initandReadCOM

我创建了一个程序来读取串行端口,绘制数据并显示值。我使用SwingWorker来收集、检查和绘制值,同时允许用户停止GUI中的数据收集。我相信当我试图绘制值并显示精确值时,我收到了修改异常

下面是doInBackground()的简化版本。我删除的行基本上是检查和比较读取的值

protected Integer doInBackground() 
    while (true && !isCancelled()) {
        value = initandReadCOM();
        // I also check and compare the value
        publish(value);
    }
    return 0;
}
然后我使用
process
命令绘制数据。我能找到的关于这个问题的最接近的线程建议使用这个

@Override
protected void process(List<Float> chunks) {
    super.process(chunks);
    float factor = chunks.get(chunks.size() - 1);
    seriesUpdated = getSeries();
    SetDataField(factor);
    this.seriesUpdated.add(new Millisecond(), factor);
}
随着程序运行更长时间,这种异常开始更频繁地出现。我们将非常感谢您的任何帮助

另外,如果您需要其他帮助,请告诉我。谢谢

编辑:下面是stacktrace

Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at java.util.Collections$UnmodifiableCollection$1.next(Unknown Source)
    at org.jfree.chart.plot.XYPlot.drawRangeMarkers(XYPlot.java:4088)
    at org.jfree.chart.plot.XYPlot.draw(XYPlot.java:3281)
    at org.jfree.chart.JFreeChart.draw(JFreeChart.java:1226)
    at org.jfree.chart.ChartPanel.paintComponent(ChartPanel.java:1612)
    at javax.swing.JComponent.paint(Unknown Source)
    at javax.swing.JComponent.paintToOffscreen(Unknown Source)
    at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
    at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
    at javax.swing.RepaintManager.paint(Unknown Source)
    at javax.swing.JComponent._paintImmediately(Unknown Source)
    at javax.swing.JComponent.paintImmediately(Unknown Source)
    at javax.swing.RepaintManager$3.run(Unknown Source)
    at javax.swing.RepaintManager$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.access$1000(Unknown Source)
    at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$200(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

您正在修改JFreeChart的数据模型,而它可能会从UI线程中访问该模型以绘制它。要解决此问题,您有不同的选项:

  • 让后台线程独立于
    JFreeChart
    s模型计算并将结果存储到
    Collection
    s中。然后在UI线程中更新模型。这是最简单的方法,将图表模型视为UI的一部分,但最终可能仍会在UI线程中完成大量工作

  • 使用多个图表模型。更新与呈现的图表当前使用的图表模型不同的图表模型。然后通过在UI线程内的图表上设置新模型来更新UI。这允许某些特定于图表的计算在后台线程中运行,并且可以通过对当前代码进行最少的更改来实现。但是,如果每次更新时都会重新计算整个图表模型,因此有相当小的增量更改,这可能会导致效率低下

  • 将整个图表代码移到后台线程中。这可能是最彻底的改变,但也是最有效的解决方案。在这个解决方案中,UI线程不再访问图表及其模型(或者只有在确保后台线程不运行的情况下)。相反,整个图表计算和渲染是在后台线程中完成的,并将其放入
    缓冲区图像中。UI线程只需将先前渲染的图像点显到屏幕上即可进行绘制。UI和后台线程之间的更新/同步仅由两个图像组成

  • 使用
    Lock
    synchronized
    块确保后台和UI线程仅在不同时间访问模型。由于您的后台威胁只包括模型更新,这实际上就像根本没有多线程一样。我只是为了完整性添加了这个选项


  • 当您在修改某个数据对象时,另一个数据对象正在读取某个数据对象时,会发生异常。找出问题所在的一种方法是在编辑/读取数据对象的方法中使用
    synchronized
    关键字。虽然这并不总是解决问题的正确方法,但它至少可以帮助您准确地找出问题发生的地方。你是不是在某个地方迭代你的arraylist然后试图修改它?由于您显示的代码不包括doInBackground中的该部分,因此我将“值”乘以单位转换因子。如果系统无法破译红色的值,我还(忘了提到)有第二次发布。但是如果您是在process()方法中询问,那么不是,process()方法是直接从代码中复制的。IYou正在修改JFreeChart的数据模型,而它可能会从UI线程中访问该模型以绘制它。所以冲突是显而易见的。谢谢你的解释。然而,由于我的初学者身份,我不知道如何实施这些建议。是否有一个示例或框架代码,我可以看看?再次感谢您的评论。
    Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
        at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
        at java.util.ArrayList$Itr.next(Unknown Source)
        at java.util.Collections$UnmodifiableCollection$1.next(Unknown Source)
        at org.jfree.chart.plot.XYPlot.drawRangeMarkers(XYPlot.java:4088)
        at org.jfree.chart.plot.XYPlot.draw(XYPlot.java:3281)
        at org.jfree.chart.JFreeChart.draw(JFreeChart.java:1226)
        at org.jfree.chart.ChartPanel.paintComponent(ChartPanel.java:1612)
        at javax.swing.JComponent.paint(Unknown Source)
        at javax.swing.JComponent.paintToOffscreen(Unknown Source)
        at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
        at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
        at javax.swing.RepaintManager.paint(Unknown Source)
        at javax.swing.JComponent._paintImmediately(Unknown Source)
        at javax.swing.JComponent.paintImmediately(Unknown Source)
        at javax.swing.RepaintManager$3.run(Unknown Source)
        at javax.swing.RepaintManager$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
        at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
        at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
        at javax.swing.RepaintManager.access$1000(Unknown Source)
        at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
        at java.awt.event.InvocationEvent.dispatch(Unknown Source)
        at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
        at java.awt.EventQueue.access$200(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.awt.EventQueue$3.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
        at java.awt.EventQueue.dispatchEvent(Unknown Source)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.run(Unknown Source)