0

I created a program to read a serial port, plot the data, and show the value. I am using a SwingWorker to collect, check, and plot the values while allowing the user to stop the data collection within the GUI. I believe I am receiving the modification exception when I try to plot the value as well as show the exact value.

Below is a simplified version of the doInBackground(). The lines I erased are essentially checking and comparing of the value read.

protected Integer doInBackground() 
    while (true && !isCancelled()) {
        value = initandReadCOM();
        // I also check and compare the value
        publish(value);
    }
    return 0;
}

I am then using the process command to plot the data. The closest thread on this problem that I could find suggested using this.

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

The SetDataField and seriesUpdated method are listed below if they are needed to help diagnose the problem.

public void SetDataField(float n) {
        this.data_.setText("Data: " + String.valueOf(n));
}

public TimeSeries getSeries() {
        return this.series;
}

As the program runs a for longer period of time this exception begins to show itself more often. Any and all help would be greatly appreciated.

Also, please let me know if you need to see anything else to help. Thanks

EDIT: Below is the 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)
Alex Wittig
  • 2,800
  • 1
  • 33
  • 42
user2755399
  • 139
  • 2
  • 4
  • 13
  • can you post stacktrace of exception – exexzian Oct 24 '13 at 16:26
  • 1
    Concurrency exceptions happen when you are modifying some data object when another data object is reading it. One way to figure out where you are having such problems is to use the `synchronized` keyword in your methods that edit/read from your data object. Although this isn't always the right way to solve a problem, it can at least help you figure out exactly where the problem is happening. See http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html. – Chill Oct 24 '13 at 16:32
  • 1
    are you somewhere iterating over your arraylist and then trying to modify it ? as the code you have shown doesn't include that part – exexzian Oct 24 '13 at 16:44
  • Within the doInBackground, I multiply the "value" by a unit conversion factor. I also (forgot to mention) have a second publish if the system can't decipher the value that was red. But if you are asking about within the process() method, then no, the process() method was copied directly from the code. I – user2755399 Oct 24 '13 at 16:58
  • You are modifying the data model of JFreeChart while it might access that model from within the UI thread in order to paint it. So the conflict is obvious. – Holger Oct 24 '13 at 17:41
  • @Holger, thank you for the response. How do I fix the conflict? – user2755399 Oct 24 '13 at 18:45

1 Answers1

0

You are modifying the data model of JFreeChart while it might access that model from within the UI thread in order to paint it. To fix this you have different options:

  1. Let the background thread calculate and store results into Collections independent from JFreeCharts model. Then update the model within the UI thread. This is the most straightforward approach, thinking of the chart model as a UI part, but you might end up still doing to much work within the UI thread.

  2. Use multiple chart models. Update a different chart model than currently used by the chart that is rendered. Then update the UI by setting the new model on the chart within the UI thread. This allows certain chart specific calculations to run in the background thread and can be implemented with the smallest number of changes to your current code. But it might turn out to be inefficient if you have rather small incremental changes as the entire chart model is recalculated on every update.

  3. Move the entire chart code into the background thread. This might be the most radical change but most efficient solution. In this solution, the chart and its model are not accessed by the UI thread anymore (or only if it is for sure that the background thread doesn’t run). Instead the entire chart calculation and rendering is done inside the background thread into a BufferedImage. The UI thread will do painting by just blitting the previously rendered image to the screen. The update/ synchronization between the UI und background thread consist of just swapping the two images.

  4. Use a Lock or synchronized block for ensuring that both, background and UI thread, access the model at different times only. Since your background threat consists of model updating only, this is effectively like having no multi-threading at all. I just added this option for completeness…

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Thank you for the explanation. However, due to my beginner status I do not know how to implement these suggestions. Is there an example or skeleton code that I can look at? Thank again for your comments. – user2755399 Oct 25 '13 at 15:09