Timeout a task with Java's SwingWorker

前端 未结 4 1307
不知归路
不知归路 2021-01-02 22:52

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

相关标签:
4条回答
  • 2021-01-02 23:26

    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.

    0 讨论(0)
  • 2021-01-02 23:28

    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);
    }
    

    }

    0 讨论(0)
  • 2021-01-02 23:29

    Any particular reason for not using the SwingWorker.get(long, java.util.concurrent.TimeUnit) ? It will throw TimeoutException that you can easily handle in your application.

    0 讨论(0)
  • 2021-01-02 23:31

    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.

    0 讨论(0)
提交回复
热议问题