Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Timeout a task with Java's SwingWorker

I am trying to implement a SwingWorker class within my application. Is there a way to set a length of time that after which, the SwingWorker "times out"? I was thinking that maybe throwing an OutOfTime exception that I can catch and then deal with. I'm just not sure how to implement it.

Thanks for all your help!

like image 579
chama Avatar asked Mar 01 '10 15:03

chama


3 Answers

Why not embed your task within a Runnable, drop it into a new single-threaded ExecutorService and then perform a get() on the resulting Future with an appropriate timeout. That would give you your timeout functionality, since get() will throw an exception if the job doesn't complete in time.

like image 134
Brian Agnew Avatar answered Nov 13 '22 03:11

Brian Agnew


The short answer is "it's hard", depending on what your requirements are. I highly recommend reading Java Concurrency In Practice.

The basic thing you could do would be to (a) make sure your SwingWorker's Runnable is interrupt-friendly, and (b) set a Timer (or use the blocking get() call Brian mentioned) to cancel your Future.

like image 1
Sbodd Avatar answered Nov 13 '22 01:11

Sbodd


The inner class MySwingWorker may well do what you need:

package com.misc;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class FutureStuffGUI extends JFrame {
/**
 * Provides a variant of SwingWorker which operates with a timeout.
 * 
 * @param <T>
 */
private static abstract class MySwingWorker<T> {

    private T result;
    private Exception raised;

    /**
     * Constructor.
     * 
     * @param timeout
     * @param timeUnit
     */
    public MySwingWorker(final long timeout, final TimeUnit timeUnit) {
        result = null;
        raised = null;

        System.out.println(Thread.currentThread().getName() + " starting");
        final FutureTask<T> future = new FutureTask<T>(new Callable<T>() {
            public T call() throws Exception {
                System.out.println(Thread.currentThread().getName() + " running");
                T result = doInBackground();
                return result;
            }
        });
        System.out.println(Thread.currentThread().getName() + " future: " + future);
        final Thread runner = new Thread(null, future, "FutureThread");
        Thread watcher = new Thread(null, new Runnable() {

            @Override
            public void run() {
                runner.start();
                try {
                    result = future.get(timeout, timeUnit);
                } catch (Exception ex) {
                    raised = ex;
                }
                SwingUtilities.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        assert SwingUtilities.isEventDispatchThread();
                        done();
                    }
                });
            }
        }, "WatcherThread");
        watcher.start();
    }

    /**
     * Implement this method as the long-running background task.
     * 
     * @return
     * @throws Exception
     */
    abstract protected T doInBackground() throws Exception;

    /**
     * This method is invoked from the UI Event Dispatch Thread on completion or timeout.
     */
    abstract protected void done();

    /**
     * This method should be invoked by the implementation of done() to retrieve
     * the result.
     * 
     * @return
     * @throws Exception
     */
    protected T get() throws Exception {
        assert SwingUtilities.isEventDispatchThread();
        if (raised != null) {
            throw raised;
        } else {
            return result;
        }
    }
}

public FutureStuffGUI() {
    super("Hello");
    init_components();
}

private void init_components() {
    JPanel panel = new JPanel();
    JButton button = new JButton("Press");
    panel.add(button);
    add(panel);
    pack();

    button.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            new MySwingWorker<String>(5, TimeUnit.SECONDS) {

                @Override
                protected String doInBackground() throws InterruptedException {
                    assert !SwingUtilities.isEventDispatchThread();
                    System.out.println(Thread.currentThread().getName() + " doInBackground");
//                        if (true) { throw new RuntimeException("Blow up"); }
                    Thread.sleep(6 * 1000);
                    return "Hello world!";
                }

                @Override
                protected void done() {
                    assert SwingUtilities.isEventDispatchThread();
                    String result;
                    try {
                        result = get();
                        System.out.println(Thread.currentThread().getName() + " done; result: " + result);
                    } catch (Exception ex) {
                        System.out.println(Thread.currentThread().getName() + " done; errored:");
                        ex.printStackTrace();
                    }
                }
            };
        };
    });
}

public static void main(String[] args) {
    FutureStuffGUI ui = new FutureStuffGUI();
    ui.setVisible(true);
}

}

like image 1
pythonologist Avatar answered Nov 13 '22 01:11

pythonologist