9.1 Swing Threading - Reference Documentation
Authors: Andres Almiray
Version: 1.2.0
9.1 Swing Threading
The Swing toolkit has a single golden rule: all long computations must be performed outside of the Event Dispatch Thread (or EDT for short). This rule also states that all interaction with UI components must be done inside the EDT, including building a component and reading/writing component properties. See Concurrency in Swing for more information.Often times this rule can be broken easily as there is no compile time check for it. The Swing toolkit offers a helper classSwingUtilities
that exposes a pair of method that let you run code inside the EDT, however there is no helper method for running code outside of the EDTSwingBuilder provides a few methods that let you build multi-threaded applications the easy way. These methods are available in Views and Controllers.
9.1.1 Synchronous Calls
Synchronous calls inside the EDT can be achieved by calling theedt{}
method. This method is smarter than plain SwingUtilities.invokeAndWait
as it won't throw an exception if called inside the EDT, on the contrary, it will simply call the block of code it was given.Example:class MyController { def model def action1 = { // will be invoked inside the EDT by default (pre 0.9.2) def value = model.value Thread.start { // do some calculations edt { // back inside the EDT model.result = … } } } def action2 = { // will be invoked outside of the EDT by default (post 0.9.2) def value = model.value // do some calculations edt { // back inside the EDT model.result = … } } }
9.1.2 Asynchronous Calls
Asynchronous calls inside the EDT can be made by calling thedoLater{}
method. This method simply posts a new event to the underlying EventQueue using SwingUtilities.invokeLater
, meaning you spare a few characters and a class import.Example:class MyController { def model def action1 = { // will be invoked inside the EDT by default (pre 0.9.2) def value = model.value Thread.start { // do some calculations doLater { // back inside the EDT model.result = … } } } def action2 = { // will be invoked outside of the EDT by default (post 0.9.2) def value = model.value // do some calculations doLater { // back inside the EDT model.result = … } } }
9.1.3 Outside Calls
The previous two examples showed a simple way to execute code outside of the EDT, simply put they spawn a new Thread. The problem with this approach is that creating new threads is an expensive operation, also you shouldn't need to create a new thread if the code is already being executed outside of the EDT.ThedoOutside{}
method takes these concerns into account, spawning a new thread if and only if the code is currently being executed inside the EDT. A rewrite of the previous example would be thusclass MyController { def model def action1 = { // will be invoked inside the EDT by default (pre 0.9.2) def value = model.value doOutside { // do some calculations doLater { // back inside the EDT model.result = … } } } def action2 = { // will be invoked outside of the EDT by default (post 0.9.2) def value = model.value // do some calculations doLater { // back inside the EDT model.result = … doOutside { // do more calculations } } } }