views:

243

answers:

2

I am writing an application in java (1.6) using swing. I currently have a JXBusyLabel on a JXLayer over the content area of my program acting as a busy indicator. I want to provide a way to allow others working with me to create a task that pops up the busy label while it's executing. The catch is, the task must be cancel-able. What is the best way to expose the functionality I desire?

Some ideas I've come up with:

  1. Raw access to setBusy()
    This is obviously the easiest for me but requires users know and understand swing threading issues.
  2. public <T> Future<T> execute(Callable<T>)
    Wraps the callable in a FutureValue that is run() on a separate thread and returns that FutureValue. The question then becomes, how to keep track of all FutureValue's generated and how to ensure that they can be cancelled. (e.g. cancel(true) always cancels)

I have never used the concurrency package in Java before and it didn't exist back when I 'learned' Java. So I am open to completely new and different ways of implementing this functionality.

Edit: Clarification of my question. I know about SwingWorker. I've just never used it. What I want to know is this:
Given a Callable (Java version of a closure?) How can I:

  1. Return the value of call() to the user w/o blocking (I think I need to use a Future for this)
  2. Tell the JXLayer to lock (starts painter), execute the supplied callable, and then unlock the JXLayer (stops painter)
  3. Ensure that, no matter what thread calls my busyExec() function, the GUI remains responsive and the background task completes. (NOTE: If I return some sort of Future object and they call get() on the event thread, it can/will block and that is ok)

I guess my main stumbling point is how to implement #2. Should I have busyExec() spin off a new thread that blocks until no background tasks are running? Should I try for some sort of queue. Is there an object that will do this all for me already?

+1  A: 

The SwingWorker (of Java 6) implements Future so it seems like it has the ability to cancel tasks via the cancel method.

More information on SwingWorker from The Java Tutorials:

coobird
A: 

Okay. For anyone interested here is what I am currently using to implement my request.

I have a method that will take a Callable<T>. It then creates a FutureTask<T> this will be returned to the caller as a this as a Future<T>. The JXBusyLabel and JXLayer are told to start painting and to lock the ui. The FutureValue and Thread (see below) is enqueued in a special list. A Runnable is created that: calls run() on the FutureTask, removes the FutureValue (and thread) from the list, and if the list is empty, unlocks the JXLayer and stops the JXBusyLabel. This Runnable is launched in a new Thread with normal priority.

When the user hits the cancel button. The list is iterated over and the FutureTasks are all canceled and removed from the list if they could be cancelled. First try cancel(false), then cancel(true). If both those means fail, the user is prompted with a warning asking them if they want to Thread.stop() the task and explains that this could make the app unstable. If yes, stop() the thread running the task. This might bring the app down. In all cases, the UI is unlocked.

The documentation for other team members states that they must be aware that the task can be killed. They are not to call get() until isDone() is true. They are explicitly told that this will basically force them to block until the task is done or cancelled. So they can't call it from the event dispatch thread.

Other solutions are still welcome

KitsuneYMG