What is SwingWorker

Swing is not thread safe as discussed with previous article. That means that any task which can take long time in execution should not be performed in Event Dispatcher Thread (EDT). Otherwise the EDT will be blocked and so the whole UI. So the solution, to perform the time intensive operations, is:

  • Start a new thread from EDT
  • Perform the heavy, time consuming task in this new thread
  • When task is done, update the Swing UI state or call any operation in EDT
  • EDT will invoke the operation

To perform above steps, we need to create a thread for time consuming task and also need to devise a mechanism to invoke the Swing Operation in EDT once the task is done (inter-thread communication). This involves some of the multi-threading code and may need to repeat it again and again with every such requirement. To abstract this code, and simplify this task; Java provides a SwingWorker class to hide all the complexities and hence the repeated work to perform these operations. It is an abstract class, which should be extended and some of its methods should be overridden to get the work done.

SwingWorker class has following important methods.

execute()
This method is the main method which should be called to start the work of SwingWorker class. As soon as you call this method, SwingWorker will give call to do the time consuming task in a new thread (described below).

doInBackground()
This method should be overridden by developer to do the time consuming task. This method will be called in a new thread, other than EDT, by SwingWorker. So any task performed on this thread won't affect the Swing UI operations. Once this method is done, result will be retained by SwingWorker which can be asked by using get() method. publish() method can also be called from this method to make the intermediate results available for GUI operations.

process()
It should be overridden if we want to process any data in EDT, as and when this data becomes available during doInBackground() operation. Suppose, one program is to load the heavy file from network which is being done in doInBackground method. Depending upon the data downloaded, you want to show the progress bar or some %age downloaded in a label on UI. This can be done by putting the work to update the label or progress bar in 'process' method. From 'doInBackground' method, we need to call the 'publish' method with the values which we want to publish; like %age data downloaded in this case. SwingWorker will call process method with this data in EDT. process method then can update the UI label. One more important point, SwingWorker may coalesced the multiple calls of publish in one call to process method, if previous calls were not executed till now. So if we are calling publish with suppose '%10', '%30', and then with '%50'; it might be possible that process method is called first with '10%' and then with '30%, 50%'. Process method should handle this case.

done()
This method is called by SwingWorker when task defined in 'doInBackground' method is finished. This is a place where final Swing UI updates should be done based on outcome from 'doInBackground' method. This method is called in EDT.

Object get()
This method is used to retrieve the result of task performed by 'doInBackground' method. Point to consider, that this method is a blocking method. So calling thread will be blocked till result is not available. So it must be used carefully, as if it is called from EDT, it will block the UI operations. One of the approach to use it could be to show model dialog box till result is received.

This way, SwingWorker class save us from defining the thread safe, and multi-threaded code again and again and work as a great utility class.

Why Swing is not Thread Safe

Big questions for Swing Developers - Why Swing is not Thread Safe? What makes Sun to design the Swing in a way that it can not handle its operation in multi-threaded environment? What if they made some extra efforts to make it thread safe, many developers would be relaxing now with comparatively simpler code? And so on..

So here is the answer. Swing is not made thread safe intentionally. It was a design decision by Swing team. Why? Because thread safety always comes at a cost. And access of Swing components in multiple threads may not be required that much.

What is thread safety and Why is that costly - Thread safety means that every part of the program should be safe to access from more than one thread concurrently. Program should be able to handle the concurrent access, either by serializing the access or ensuring that it is not disrupting the shared states or operations. Serializing the access means that access should be synchronized for access by thread, which will ensure that only one thread access the code block at a time after taking the necessary lock and hence guarantee the safe access to shared states. Or design has to be done in a way that program block does not affect any shared state or won't disrupt any operations due to concurrent access to states. Both of these changes are costly in term of performance or/and application design/development.

Why Multiple Thread Access may not be required - Because most of the UI operations are done in event fired by UI itself which are sequential in nature. There are few cases when we want to touch UI functions or states in parallel threads, like if we want to perform some time intensive operation to load the data and want to keep the UI active. But these cases are limited.

So if requirement to work in multi-threaded environment is very limited, and cost to make the code ready for multi-threaded environment is high; rationale is not to implement it. However, there should be provision using which developers can manage the UI operations in multiple threads environment also as mentioned above in case of loading heavy data in parallel.

This is what Swing Team analyzed and decided. Result is a high performing GUI development library for most of the scenarios with a capability to work with multiple threads also if required.