If you see an inconsistent / corrupt image it is sometimes indicative of updating the data set on a thread other than the Event Dispatch Thread. I suggest you add some assert statements to verify this:
assert SwingUtilities.isEventDispatchThread();
Also, note that JFreeChart isn't particularly efficient as it re-renders the entire graph whenever a new data point is added. One optimisation you could make here is:
- If your app consists of multiple charts then only propagate
DatasetChangeEvent
s for the chart currently being displayed. If a chart is hidden (e.g. on a different tab) then simply record the fact that it is stale and needs to be rerendered when the tab is selected.
EDIT
Based on your comment to Dan's response it sounds like your I/O thread receiving messages is also updating the JFreeChart dataset, when in fact the update should be performed on the Event Dispatch Thread (and messages should be performed on a separate I/O thread). To achieve this I suggest you use a throttle based approach whereby I/O events are bucketed together. You could use a BlockingQueue
to achieve this; e.g.
// Message definition containing update information.
public interface Message { ... }
// BlockingQueue implementation used to enqueue updates received on I/O thread.
BlockingQueue<Message> msgQ = ...
// Method called by I/O thread when a new Message is received.
public void msgReceived(Message msg) {
boolean wasEmpty = msgQ.isEmpty();
msgQ.add(msg);
// Queue was empty so need to re-invoke Swing thread to process queue.
if (wasEmpty) {
// processUpdates is a re-useable Runnable defined below.
SwingUtilities.invokeLater(processUpdates);
}
}
// Runnable that processes all enqueued events. Much more efficient than:
// a) Creating a new Runnable each time.
// b) Processing one Message per call to run().
private final Runnable processUpdates = new Runnable() {
public void run() {
Message msg;
while ((msg = msgQ.poll) != null) {
// Add msg to dataset within Event Dispatch thread.
}
}
}