I have what I imagine is a fairly typical JavaFX application (once it's released I'll post more about it). It has a GUI, some mostly asynchronous state management, and interactions with various servers that can change the apps state.
At first I tried the simple and obvious approach in which the backend would schedule closures onto the UI thread using Platform.runLater() when things changed, sometimes via ad-hoc event handlers or callbacks. But it ended up getting more and more complicated and unclear. So I ended up rewriting things to be more actor-ish in which the backend code ran mostly in its own thread and vended "mirrored observables". I figured mirrored observables are a generally useful concept that probably JavaFX should have itself. The idea is simple enough. Given an ObservableList or ObservableSet (I didn't need map yet), calling a static utility function with that list and an Executor returns a new list in which all updates run in the context of that executor. This means a piece of code that's responding to changes in state held elsewhere e.g. via a network connection which receives updates from a server can have its own thread, and update its own ObservableLists/Sets/Maps without thinking about threading as long as the only public accessors for these collections vend mirrored versions. Note that mirrors are read-only, I don't attempt to do two-way sync (with conflict resolution?!). If you want to update the "real" list you have to schedule a closure onto the backend thread to do it and wait for the change to re-propagate to the frontend thread. Once this is in place, you can then bind the collections to UI controls using some extra transformers in the standard manner, and everything hangs together nicely. The code I'm using is here (Apache licensed, go wild) https://gist.github.com/mikehearn/4781ce7f00228762adfb There are three files. AffinityExecutor is an extended version of the Executor interface which has a notion of thread ownership (supports short circuiting and assertions), along with static methods to create: 1. AffinityExecutors that are bound to a dedicated new thread with a task queue. 2. An AffinityExecutor that queues up tasks but doesn't execute them until explicitly requested, this is useful for unit testing. 3. An AffinityExecutor that wraps Platform.runLater and Platform.isFxApplicationThread 4. An executor that just runs closures immediately on the same thread. Then ObservableMirrors creates sets/lists in the same way a content binding would, but which re-applies changes in the given thread or short-circuits and does so immediately if the listener on the mirror is running on the same thread as the caller. There's also a set of static addListener methods in MarshallingObservers that just relays into the right thread as well, if you only care about changes and not full content. Of course you could have an ObservableMirrors equivalent that uses a regular Java executor, you'd just lose some safety and short circuiting.
