This page contains a technical overview of Swing Threading, explaining how it is that we make all of this work.
It may be surprising to know that it only takes a few hundred lines of code to make everything happen! In fact, our test cases have more lines of code than the rest of the project!
If you use Swing Threading at all, you'll notice something that sets it apart from other threading solutions: it almost seems like everything is happening on the same thread. You can obtain return values from off-EDT methods just as you would from any other method without having to use Futures or any other threading nonsense. And yet, the GUI doesn't freeze during these time-consuming, non-EDT tasks! And, when the non-EDT method returns, the method that called it just keeps on executing as if nothing had happened! How does this work?
Our man behind the curtains is the brilliant Foxtrot library, which handles all of the semi-synchronicity for us. What the folks at Foxtrot have managed to do is re-implement the Swing/AWT Modal Dialog code, which allows a certain EDT task to be paused and moved off to the side while other EDT tasks are executed, then be placed back onto the Event queue once the associated background task has been completed. What this means for you is that everything executes just like a normal method call, even though the actual work is being done on a different thread, all without clogging up the EDT and thereby freezing the UI.
When a call is made from a non-EDT thread to a @DoOnEDT-annotated method, we simply use SwingUtilities.invokeAndWait() to pause the calling thread.
In order to run annotated methods on the proper threads, we use AspectJ pointcuts to wrap calls to the annotated methods. We read the configuration options passed in the annotation, then create and run any necessary threads or Foxtrot Workers. The pointcuts we use are:
execution(@net.java.swing.threading.annotation.DoInBackground * * (..)) execution(@net.java.swing.threading.annotation.DoInBackground new(..))
and, for @DoOnEDT:
execution(@net.java.swing.threading.annotation.DoOnEDT * * (..)) execution(@net.java.swing.threading.annotation.DoOnEDT new(..))
You will notice that these pointcuts include constructor methods. This means that you can even have constructors that run on certain threads. This is especially useful when using IoC containers, like Spring, to control the creation of your Swing components.