SyncModel Aspect

Can some of Swing threading with rules be managed by an aspect? Maybe, maybe not. I set out a few weeks ago to try and see if I could make long, or GUI freezing, tasks execute off of the Event Dispatch Thread (EDT) and when complete, return the results to the EDT.

Swing Worker as an Aspect

My first approach at this was to try and wrap a SwingWorker within an aspect. Functionally, this works in that the code would execute and the value would return successfully. However, this approach didn’t do much for keeping the GUI responsive. Since the aspect can’t make good use of the finished() method, you have to call the get() method – which blocks. There is probably some type of convoluted solution that would involve inter-type declarations, etc. But when things get overly complex like that, it’s a good indicator that this isn’t the solution.

The Spin Project

I ran across the Spin Project a while back, and it does some neat things. The Spin project used the Synchronous Model technique, whose origin has been credited to the FoxTrot project. Spin does a really good job of transparently executing threads without freezing the GUI, and it’s fairly easy to implement. Basically, Spin work like this:

Spin is built on top of virtual proxies and a technique borrowed from the java.awt.Dialog component. While a modal dialog has to wait for user input, the EDT is rerouted to the swing event processing to handle further events.”

I thought that was an interesting approach, but one thing I didn’t like about Spin is that you can’t just “Spin” a single method, the entire class must be proxied.

The Sync Model Aspect

Spin does a lot of great stuff but I wanted something that could be even easier to implement. I wanted to be able to:

  1. Only “Spin” methods marked with an annotation, don’t proxy the entire class

  2. Avoid the need to work with interfaces or proxies.

There is a lot in Spin that handles the creation and evaluation of the proxies and which has little to do with executing the threads. To make a long story short, I basically gutted the Spin code base and ended up with 3 classes:

  1. The Dispatcher – this is nearly identical code to that found in Spin code base

  2. SyncModel Annotation – An annotation that is used to identify methods that will get executed through the aspect

  3. SyncModel Aspect – The aspect that does the actual work.

And that’s it! The code executes in a similar manner as it would under Spin, but without the proxying code. By simply doing something like this:

     ...    
     @SyncModel    
     public void doCalc() {       
          // long calculation done here       
	  ...    
     } 
     ....

By annotating the doCalc() method with the @SyncModel annotation, the execution will be carried out by the aspect an the GUI will remain responsive. You can see a demo of how this works by having a look at the Handy Aspect Library Demo. The sources are available from the Handy Aspects Project page.

Conclusion

Use this aspect with caution. Admittedly, the Spin folks have spent a lot more time looking at the internals of the event dispatcher than I have. This Dispatcher class calls JDK code that is not public and may change in a future release. Also, this aspect comes with all of the same caveats as Spin, so please have a look at the Spin home page for more details.

With all of that said, I don’t know that AOP can really solve all of your swing threading issues. While the aspect does work rather well, this is not a good solution for tasks that need to be able to be canceled or used in a progress bar. But for short little tasks that can cause brief lockups in the GUI, this could be a reasonable solution.

Be Sociable, Share!