ConcurrentModificationException when XYPlot drawing markers

A discussion forum for JFreeChart (a 2D chart library for the Java platform).
Locked
tmtjond
Posts: 23
Joined: Thu Jul 24, 2008 3:21 am

ConcurrentModificationException when XYPlot drawing markers

Post by tmtjond » Thu Jul 23, 2009 4:22 am

Current situation:
The chart will be kept redrawing as dataset will be updated as time goes by.
At the same time, the collection of markers may be updated on demand.

On very rare case, it would throw "ConcurrentModificationException" when XYPlot is iterating the markers during drawing if marker is added at that time.

Just see if it is necessary to synchronize the collection ?
Or should notify the chart to stop drawing the plot until the marker is added? (which methods should be called)

Thanks for your advice.

michael watts
Posts: 3
Joined: Tue Feb 15, 2011 2:40 pm
antibot: No, of course not.

Re: ConcurrentModificationException when XYPlot drawing markers

Post by michael watts » Tue Feb 15, 2011 2:54 pm

I too have a problem in this regard... here's the essence of a stack trace I see from time to time:

Code: Select all

Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
	at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
	at java.util.AbstractList$Itr.next(AbstractList.java:343)
	at org.jfree.chart.plot.XYPlot.drawAnnotations(XYPlot.java:3981)
	at org.jfree.chart.plot.XYPlot.draw(XYPlot.java:3385)
....
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:136)
I am extending ChartPanel and I have tried loads of different tactics including wrapping the annotations list in a SynchronizedList and using that for locking and access, for each method that makes any changes to the plot, using ReentrantLock, adding 'synchronized' in the signature and lately synchronizing on the plot object.

The exception I see is always the same, calling drawAnnotations from an awt.EventDispatchThread. Does anyone have some idea of what I can implement to prevent this?

TIA, Mike Watts

michael watts
Posts: 3
Joined: Tue Feb 15, 2011 2:40 pm
antibot: No, of course not.

Re: ConcurrentModificationException when XYPlot drawing markers

Post by michael watts » Fri Feb 18, 2011 12:54 pm

As this has a very complicated answer and no-one else saw fit to provide even a pointer, I thought I'd document some notes and a solution for any poor souls with the same problem in the future.

First some background, the process used in my case, some recommended reading and a solution.

You probably know this already, as I did, that this is not a 'JFreeChart' thing but a 'Swing' thing... but because JFreeChart is a much more complex beast than most swing components used in daily life it is more likely to happen with this [sort of] component. I also knew it was a multiple-thread issue, just not how to synchronize with the swing thread.

The setup I have is complex: multiple threads monitoring an engineering process which is asynchronous to the program. Events are raised by these threads using a typical EventListener interface being sent an EventObject from the 'monitor'. The event listener processes the data and adds a new point to the chart ( and is the only publicly used method in the 'graph' class ). So the problem then was that the 'monitor' thread was occasionally updating the chart whilst the Swing thread was doing something itself ( not sure what to be honest ).

After some research I came to understand I needed to link into the AWT event dispatching thread and found a couple of useful articles:
http://java.sun.com/products/jfc/tsc/ar ... eads1.html
http://java.sun.com/products/jfc/tsc/ar ... eads2.html

Having a quick look at the second, which describes the SwingWorker and a link to the source code, I decided that this was not the best way to go in this case, but ( interestingly ) the SwingWorker makes a call to SwingUtilities.invokeLater(), described more fully in the first article, which looks like the ticket.

So - my solution looks like this:

Code: Select all

public void handleEvent(final InterestingEvent ev) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            graph.addPoint(ev.getX(), ev.getY());
        }
    });
}
The 'final' keyword in the argument list is required.

I hope this helps someone!

Locked