Prevent Swing GUI locking up during a background task

Simonw picture Simonw · Jun 2, 2009 · Viewed 14.3k times · Source

I have a swing application which stores a list of objects. When the users clicks a button,

I want to perform two operations on each object in the list, and then once that is complete, graph the results in a JPanel. I've been trying SwingWorker, Callable & Runnable to do the processing, but no matter what I do, while processing the list (which can take up to a few minutes, as it is IO bound), the GUI is locked up.

I have a feeling it's probably the way I'm calling the threads or something, or could it be to do with the graphing function? That isn't threaded as it is very quick.

I have to do the two processing stages in order too, so what is the best way to ensure the second one has waited on the first? I've used join(), and then

while(x.isAlive())  
{  
        Thread.sleep(1000);  
}

to try and ensure this, but I'm worried this could be the cause of my problem too.

I've been looking everywhere for some pointers, but since I can't find any I'm sure I'm doing something stupid here.

Answer

jjnguy picture jjnguy · Jun 2, 2009

The problem is, your long running task is blocking the Thread that keeps the GUI responsive.

What you will need to do is put the long running task on another thread.

Some common ways of doing this are using Timers or a SwingWorker.

The Java tutorials have lots of information regarding these things in their lesson in concurrency.

To make sure the first task finishes before the second, just put them both on the same thread. That way you won't have to worry about keeping two different threads timed correctly.

Here is a sample implementation of a SwingWorkerFor your case:

public class YourTaskSwingWorkerSwingWorker extends SwingWorker<List<Object>, Void> {
    private List<Object> list
    public YourClassSwingWorker(List<Object> theOriginalList){
        list = theOriginalList;
    }

    @Override
    public List<Object> doInBackground() {
        // Do the first opperation on the list
        // Do the second opperation on the list

        return list;
    }

    @Override
    public void done() {
        // Update the GUI with the updated list.
    }
}

To use this code, when the event to modify the list is fired, create a new SwingWorker and tell it to start.