Dec 18, 2009

SwingWorker details – canceling background tasks in flight

http://developerlife.com/tutorials/?p=38


Introduction

f you use the SwingWorker class to run background tasks that don’t freeze up the EDT (Event Dispatch Thread) in your Swing apps, this may be of interest. What happens when you cancel a long running operation that’s running the background? For eg, a user might generate an event that causes a SwingWorker to be created that starts running some code in the background. What happens when the user wants to cancel this long running background operation? This is what we will delve into in this tutorial and get the answer to this question.

You can learn more about threads in this chapter of the Concurrency in Practice book (on Safari Books Online). You can learn more about the Event Dispatch Thread (EDT) in this chapter of the Filthy Rich Clients (on Safari Books Online).
The setup

Let’s say you have some code that you want to run in the background (on a thread that is not the EDT). So this is what you would do. You would subclass SwingWorker and put your code in the doInBackground() method. Here’s an example:

1: SwingWorker myWorker = new SwingWorker() {

2: protected String doInBackground() throws Exception {

3: while (!isCancelled()) {

4: //run some code in the background…

5: }

6: return “something”;

7: }

8: @Override protected void done() {

9: try {

10: String value = get();

11: }

12: catch (InterruptedException e) {}

13: catch (ExecutionException e) {}

14: catch (CancellationException e) {}

15: }

16: };

The first type parameter for our SwingWorker subclass is String, and this defines the type of object that is returned when done() is called… which happens when the background thread completes it’s execution. The second parameter is just Void, since I’m not going to use this SwingWorker to post intermediate results to the EDT for processing (while the background thread is running). Click here for more details on this. Sun’s Java Tutorial has more information on SwingWorker if you need more background information. Note the use of isCancelled() in the while loop… we will cover this in more detail in the sections that follow. The results of this background processing are retrieved on the EDT in the done() method – also note the exceptions, we will cover this in the next sections as well.

To run this snippet, all you have to do is:

1: myWorker.execute()

To cancel it, all you have to do is:

1: myWorker.cancel()

The tale of two threads

When you call execute() on myWorker, from the EDT or whatever thread the execute() call is running in, two things happen:

1. a thread is created that runs the SwingWorker (let’s call this Thread1).
2. another thread is created by this SwingWorker instance which runs your code in the background (let’s call this Thread2).

Let’s say that you want to cancel the background task because it is taking too long. You would then call cancel() on myWorker. When you call cancel() on the SwingWorker instance myWorker, the following things happen concurrently:

1. CancellationException gets raised on Thread1 (the SwingWorker thread). So the SwingWorker thread itself jumps out of waiting for doInBackground() method to end, and goes straight into done(). When the get() method is called, this causes a CancellationException to be thrown on the SwingWorker thread itself, and you can catch this in the CancellationException handler. So the SwingWorker thread ends its lifecyle at this point.
2. InterruptedException gets raised on Thread 2 (the thread that’s actually running your code in the background). If your code is not interruptible, or if you catch the InterruptedException and just keep going, then this thread will not die, and will continue doing it’s background processing! This is why it’s necessary to check to see if isCancelled() is true. This is the only way (outside of responding to an InterruptedException) that can cause the background thread to stop running your code. Also, when your background task completes execution and it returns the String, nothing will happen, since the SwingWorker (Thread1) that was supposed to respond to this (in it’s done() method) is already dead. If you use call sleep() or wait(), then these methods will respond to an InterruptedException being raised, otherwise, the only way to tell is by checking isCancelled(). So it’s pretty easy, if you’re not careful, for the underlying thread executing your background code and the SwingWorker thread itself to get out of “sync”. Also, if you have code that’s doing some network IO, you have to use an InputStream or OutputStream that can check the isCancelled() method to break the IO operation. If you can’t do this, then you can try closing the underlying IO streams and causing an IOException to occur when isCancelled() is detected.

Closing thoughts

In your Swing apps that use SwingWorker to perform lengthy background tasks, it’s necessary to keep in mind that just because you called cancel() on the SwingWorker doing your task in the background that it’s been “cancelled”. Java does not have preemptive multithreading – only cooperative. So it’s your onus to check the isCancelled() method in your doInBackground() code, and do the proper exception handling in the done() method of the SwingWoker to make sure that you don’t have a thread leak. Also, it’s important to process results from your background operation in the done() method – this will ensure that the 2 threads won’t go out of “sync”. Since the SwingWorker thread can be cancelled without the underlying execution thread knowing, it’s important to perform any changes to your system in the done() method – if the SwingWorker get’s cancelled, then these changes won’t show up in your system.
Training Services

Want to learn from the best in the business? We have training programs available for BlackBerry development, Android development, rich desktop apps, and UX design. We can give your development team a competitive edge, and make them experts in these technologies. Contact us if you are interesting in learning more about our training services & schedule.
Consulting Services

If you need help building web, mobile, and desktop apps that are all connected to the cloud, we can help. We can empower your business by bringing your ideas to life. Contact us if you have a project you need our help with and we will consider taking you on as a client.

Our expertise: architecture, UX design, graphic design, and implementation services for BlackBerry, Android, GWT, desktop Java, and cloud computing. Our specialties: crafting stunning UXes, LBS, real-time collaboration and syncing between services and web/mobile/desktop apps, location based mobile e-commerce, and location based mobile advertising.
Further reading in related categories
Graphics

Task API (3 of 5) - Monitoring HTTP POST operations
Using Task API to perform HTTP POST operation in the background, while monitoring the request and response I/O operation data streams.
Task API (2 of 5) - Task API in-depth
More details on the Task API introduced in the first Task API tutorial. SampleApp from the first tutorial is dissected under a microscope along with the API itself. Also contains information on which external libraries are optional and which are required.
Task API (1 of 5) - Quick Start Guide
Introducing the Task API. Easy to use background task API for Swing. Android and JavaME implementation coming soon. Easily create tasks and monitor their progress and cancel them at any time. Easily manage multiple tasks. Create network aware tasks and recurring tasks, and much much more! The API is open source (Apache 2.0 license). Enjoy!!!
SwingX Tutorial - Busy Label (JXBusyLabel)
This tutorial will show you how to use SwingX's JXBusyLabel component to display an indeterminate progress indicator. It will also show you advanced configuration options that allow you to create different and interesting indeterminate progress indicators using the BusyPainter.
SwingX Tutorial - Task Pane (JXTaskPane, Container)
This tutorial will walk you through the steps required to use JXTaskPane and JXTaskPaneContainer in SwingX. You will learn how to change the default color schemes of these components, and add components and actions to task panes.
SwingX Tutorial - Painters
This tutorial will introduce you to the SwingX API and the concept of Painters. It will give you an idea of the kinds of effects you can create with them as well, with code examples.
How to use the AnimatedTransition API (SwingX and Timingframework)
I needed to perform animations in the app that I'm building (http://screamingtoaster.com). I needed to build animations that show a transition from one screen to another. This is slightly different than creating custom, or modified components which perform a function and have a set of graphical effects. I needed animations that would transition my user interface from one "screen" to the next. The screens themselves could be panels or components (part of the whole app, or the entire app itself). While I'd been writing much of this code myself, to do these animations, it just got really tedious and frustrating to add this level of complexity to my code, when all I needed were some simple animations. I've been using the SwingX API and the TimingFramework API to perform the animations and leverage the components, however, this last piece was missing. And this last piece just got delivered by Chet Haase, as a part of the binary deliverables with his (and Romain Guy's) great book - Filthy Rich Clients.
How to use glass pane for animation (SwingX and Timingframework)
I needed to perform animations in the app that I'm building (http://screamingtoaster.com). I needed to build animations that move various components around on the screen, and other animations that pop up components on top of existing components, etc. After creating a few of these effects, I realized that I was doing the same thing over and over again, which is why I decided to write this tutorial to encapsulate this pattern, in the hopes that I will help others doing the same thing.
Creating multi-threaded Swing apps that consume web services
If you've ever want to incorporate web services into your graphical applications/applets/widgets written in Java, then there are some threading issues that you have to be mindful of, and design around. This tutorial will guide you though some of the important threading issues you have to keep in mind when building such applications. The strategies outlined in this tutorial apply to accessing more than just web services from Swing apps; it also applies to loading information from databases, and performing any other kind of time consuming process that has to happen in the desktop app and interact with it, but can't make the user interface unresponsive.

Multithreading, Concurrency

How to build a service-enabled Android app - Part 3/3 Multithreading
I've written 3 tutorials to show you how to create a service enabled Android application that performs all of it's network I/O in a background thread (not the UI thread). These tutorials are split into three parts. This tutorial shows you how to use background threads to perform long running network IO operations, so that the main UI thread is not locked up.
Task API (3 of 5) - Monitoring HTTP POST operations
Using Task API to perform HTTP POST operation in the background, while monitoring the request and response I/O operation data streams.
Task API (2 of 5) - Task API in-depth
More details on the Task API introduced in the first Task API tutorial. SampleApp from the first tutorial is dissected under a microscope along with the API itself. Also contains information on which external libraries are optional and which are required.
Task API (1 of 5) - Quick Start Guide
Introducing the Task API. Easy to use background task API for Swing. Android and JavaME implementation coming soon. Easily create tasks and monitor their progress and cancel them at any time. Easily manage multiple tasks. Create network aware tasks and recurring tasks, and much much more! The API is open source (Apache 2.0 license). Enjoy!!!
Creating multi-threaded Swing apps that consume web services
If you've ever want to incorporate web services into your graphical applications/applets/widgets written in Java, then there are some threading issues that you have to be mindful of, and design around. This tutorial will guide you though some of the important threading issues you have to keep in mind when building such applications. The strategies outlined in this tutorial apply to accessing more than just web services from Swing apps; it also applies to loading information from databases, and performing any other kind of time consuming process that has to happen in the desktop app and interact with it, but can't make the user interface unresponsive.
Introduction to Java 5 java.util.concurrent API
Introduction to the Java5 Concurrency API
Advanced Threads
Advanced threading topics.
Introduction to Threads
Introduction to multithreading in Java.

No comments: