Leon Atherton

Leon is a developer at IDRsolutions and product manager for BuildVu. He is responsible for managing the BuildVu product strategy and roadmap, and also spends a lot of his time writing code to build new features, improve functionality, fix bugs, and improve the testing for BuildVu.

Handling Threads & Concurrency in JavaFX

2 min read

Recently, while converting the PageFlow mode from Java3D to JavaFX in our Java PDF Viewer, I came across some ConcurrentModificationException issues, so thought it worthwhile sharing what I have learnt from fixing them.

To explain what I was doing, I was putting ImageViews onto the scene and using MouseEvents to move the Images around the scene. One of my MouseEvents made use of a Thread in order to continue moving images even when the images were no longer being clicked on.

Despite making sure that I would never concurrently ask the scene to do multiple things at once, I was still randomly receiving ConcurrentModificationExceptions as below:

Exception in runnable
java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:394)
at java.util.LinkedHashMap$KeyIterator.next(LinkedHashMap.java:405)
at javafx.scene.Parent.recomputeBounds(Parent.java:1526)
at javafx.scene.Parent.impl_computeGeomBounds(Parent.java:1275)
at javafx.scene.layout.Region.impl_computeGeomBounds(Region.java:2517)
at javafx.scene.Node.updateGeomBounds(Node.java:3142)
at javafx.scene.Node.getGeomBounds(Node.java:3102)
at javafx.scene.Node.getLocalBounds(Node.java:3084)
at javafx.scene.Node.containsBounds(Node.java:3430)
at javafx.scene.layout.Region.impl_pickNodeLocal(Region.java:2378)
at javafx.scene.Node.impl_pickNode(Node.java:3931)
at javafx.scene.Scene$MouseHandler.pickNode(Scene.java:3454)
at javafx.scene.Scene$MouseHandler.access$2000(Scene.java:3119)
at javafx.scene.Scene.pick(Scene.java:1736)
at javafx.scene.Scene.access$6900(Scene.java:169)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3284)
at javafx.scene.Scene$MouseHandler.access$8100(Scene.java:3119)
at javafx.scene.Scene$MouseHandler$1.run(Scene.java:3152)
at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:173)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
at java.lang.Thread.run(Thread.java:722)

The stack trace is not terribly helpful as the exception does not occur in my code, but after some research, it was quite clear that the issue is that the scene is NOT thread safe.

There are a couple of good resources worth reading if you are thinking of using threads in JavaFX, for example a Concurrency in JavaFX article from Oracle, or Richard Bair’s blog article on Worker Threads in JavaFX that is a little out of date, but which led me to the best resource that is in fact the API documentation for the Task class.

There is a long list of examples, but the most important one for me was one very near the end: A Task Which Modifies The Scene Graph.

 final Group group = new Group();
 Task<Void> task = new Task<Void>() {
     @Override protected Void call() throws Exception {
         for (int i=0; i<100; i++) {
             if (isCancelled()) break;
             final Rectangle r = new Rectangle(10, 10);
             r.setX(10 * i);
             Platform.runLater(new Runnable() {
                 @Override public void run() {
                     group.getChildren().add(r);
                 }
             });
         }
         return null;
     }
 };

So, if you are modifying the Scene Graph from within a Thread, you need to use Platform.runLater() in order to avoid any unwanted Exceptions.

It is also worth a reminder that if you are using a boolean declared and used outside a thread that also gets used in a thread, make sure to use the volatile keyword to disable any unwanted caching or other optimisations.

I have written several articles on converting our Java3D usage into JavaFX and you can read the other articles here.

Leon Atherton

Leon is a developer at IDRsolutions and product manager for BuildVu. He is responsible for managing the BuildVu product strategy and roadmap, and also spends a lot of his time writing code to build new features, improve functionality, fix bugs, and improve the testing for BuildVu.

Updates on Java PDF Viewer roadmap from IDRsolutions

My previous blog post (5 changes we are considering in 2016 for IDRsolutions), generated lots of feedback for us (for which we would like...
Mark Stephens
57 sec read

My key takeaways from NetBeans Day 2015

NetBeans Day 2015 had to be rescheduled to bigger rooms because of attendee demand. It was a very busy schedule. Here are my notes...
Mark Stephens
2 min read

An Introduction to JavaFX Panes with Code Examples

As a developer at IDR Solutions I spend a lot of my time working with JavaFX and Panes in our JavaFX PDF Viewer. I...
Sylwia Dorota Kedzia
1 min read

Leave a Reply

Your email address will not be published. Required fields are marked *