java 如何取消 SwingWorker 的执行?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6113944/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 14:22:50  来源:igfitidea点击:

How cancel the execution of a SwingWorker?

javamultithreadingswingswingworkercancellation

提问by Renato Dinhani

Currently I have two SwingWorker threads doing job on background. If an exception occurs, the method stop to work, but the thread still runnig.

目前我有两个 SwingWorker 线程在后台工作。如果发生异常,该方法将停止工作,但线程仍在运行。

How I do to stop the execution and kill the thread of the doInBackground()if an exception occurs?

doInBackground()如果发生异常,如何停止执行并终止线程?

this.cancel(true)don't destroy/close the thread. How can I achieve this?

this.cancel(true)不要破坏/关闭线程。我怎样才能做到这一点?

@Override
protected Boolean doInBackground() throws Exception {
        try {
            while (true) {
                //some code here                   
                return true;
            }
        } catch (Exception e) {       
            this.cancel(true); //<-- this not cancel the thread               
            return false;
        }
    }

I see these threads in the debug of Netbeans.

我在 Netbeans 的调试中看到了这些线程。

'AWT-EventQueue-0' em execu??o
'AWT-Windows' em execu??o
'SwingWorker-pool-1-thread-1' em execu??o
'SwingWorker-pool-1-thread-2' em execu??o

//*em execu??o = in execution

回答by mKorbel

as jzd montioned, there is method cancel(boolean mayInterruptIfRunning); for exapmle

正如 jzd 所指出的,有方法cancel(boolean mayInterruptIfRunning);例如

EDIT: with cancel(true); you have to (always) cautgh an exception java.util.concurrent.CancellationException

编辑:取消(真);你必须(总是)抓住一个例外java.util.concurrent.CancellationException

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

public class SwingWorkerExample extends JFrame implements ActionListener {

    private static final long serialVersionUID = 1L;
    private final JButton startButton, stopButton;
    private JScrollPane scrollPane = new JScrollPane();
    private JList listBox = null;
    private DefaultListModel listModel = new DefaultListModel();
    private final JProgressBar progressBar;
    private mySwingWorker swingWorker;

    public SwingWorkerExample() {
        super("SwingWorkerExample");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new GridLayout(2, 2));
        startButton = makeButton("Start");
        stopButton = makeButton("Stop");
        stopButton.setEnabled(false);
        progressBar = makeProgressBar(0, 99);
        listBox = new JList(listModel);
        scrollPane.setViewportView(listBox);
        getContentPane().add(scrollPane);
        //Display the window.
        pack();
        setVisible(true);
    }
//Class SwingWorker<T,V> T - the result type returned by this SwingWorker's doInBackground
//and get methods V - the type used for carrying out intermediate results by this SwingWorker's 
//publish and process methods

    private class mySwingWorker extends javax.swing.SwingWorker<ArrayList<Integer>, Integer> {
//The first template argument, in this case, ArrayList<Integer>, is what s returned by doInBackground(), 
//and by get(). The second template argument, in this case, Integer, is what is published with the 
//publish method. It is also the data type which is stored by the java.util.List that is the parameter
//for the process method, which recieves the information published by the publish method.

        @Override
        protected ArrayList<Integer> doInBackground() {
//Returns items of the type given as the first template argument to the SwingWorker class.
            if (javax.swing.SwingUtilities.isEventDispatchThread()) {
                System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() returned true.");
            }
            Integer tmpValue = new Integer(1);
            ArrayList<Integer> list = new ArrayList<Integer>();
            for (int i = 0; i < 100; i++) {
                for (int j = 0; j < 100; j++) { //find every 100th prime, just to make it slower
                    tmpValue = FindNextPrime(tmpValue.intValue());
//isCancelled() returns true if the cancel() method is invoked on this class. That is the proper way
//to stop this thread. See the actionPerformed method.
                    if (isCancelled()) {
                        System.out.println("SwingWorker - isCancelled");
                        return list;
                    }
                }
//Successive calls to publish are coalesced into a java.util.List, which is what is received by process, 
//which in this case, isused to update the JProgressBar. Thus, the values passed to publish range from 
//1 to 100.
                publish(new Integer(i));
                list.add(tmpValue);
            }
            return list;
        }//Note, always use java.util.List here, or it will use the wrong list.

        @Override
        protected void process(java.util.List<Integer> progressList) {
//This method is processing a java.util.List of items given as successive arguments to the publish method.
//Note that these calls are coalesced into a java.util.List. This list holds items of the type given as the
//second template parameter type to SwingWorker. Note that the get method below has nothing to do with the 
//SwingWorker get method; it is the List's get method. This would be a good place to update a progress bar.
            if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
                System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false.");
            }
            Integer percentComplete = progressList.get(progressList.size() - 1);
            progressBar.setValue(percentComplete.intValue());
        }

        @Override
        protected void done() {
            System.out.println("doInBackground is complete");
            if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
                System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false.");
            }
            try {
//Here, the SwingWorker's get method returns an item of the same type as specified as the first type parameter
//given to the SwingWorker class.
                ArrayList<Integer> results = get();
                for (Integer i : results) {
                    listModel.addElement(i.toString());
                }
            } catch (Exception e) {
                System.out.println("Caught an exception: " + e);
            }
            startButton();
        }

        boolean IsPrime(int num) { //Checks whether a number is prime
            int i;
            for (i = 2; i <= num / 2; i++) {
                if (num % i == 0) {
                    return false;
                }
            }
            return true;
        }

        protected Integer FindNextPrime(int num) { //Returns next prime number from passed arg.       
            do {
                if (num % 2 == 0) {
                    num++;
                } else {
                    num += 2;
                }
            } while (!IsPrime(num));
            return new Integer(num);
        }
    }

    private JButton makeButton(String caption) {
        JButton b = new JButton(caption);
        b.setActionCommand(caption);
        b.addActionListener(this);
        getContentPane().add(b);
        return b;
    }

    private JProgressBar makeProgressBar(int min, int max) {
        JProgressBar progressBar1 = new JProgressBar();
        progressBar1.setMinimum(min);
        progressBar1.setMaximum(max);
        progressBar1.setStringPainted(true);
        progressBar1.setBorderPainted(true);
        getContentPane().add(progressBar1);
        return progressBar1;
    }

    private void startButton() {
        startButton.setEnabled(true);
        stopButton.setEnabled(false);
        System.out.println("SwingWorker - Done");
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if ("Start" == null ? e.getActionCommand() == null : "Start".equals(e.getActionCommand())) {
            startButton.setEnabled(false);
            stopButton.setEnabled(true);
// Note that it creates a new instance of the SwingWorker-derived class. Never reuse an old one.
            (swingWorker = new mySwingWorker()).execute(); // new instance
        } else if ("Stop" == null ? e.getActionCommand() == null : "Stop".equals(e.getActionCommand())) {
            startButton.setEnabled(true);
            stopButton.setEnabled(false);
            swingWorker.cancel(true); // causes isCancelled to return true in doInBackground
            swingWorker = null;
        }
    }

    public static void main(String[] args) {
// Notice that it kicks it off on the event-dispatching thread, not the main thread.
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                SwingWorkerExample swingWorkerExample = new SwingWorkerExample();
            }
        });
    }
}

回答by jfpoilpret

By default, SwingWorkerreuses worker threads, so it is perfectly normal that, even though, doInBackground()has returned, to still see the thread that executed your method.

默认情况下,SwingWorker重用工作线程,因此即使doInBackground()已经返回,仍然可以看到执行您的方法的线程是完全正常的。

You can identify this fact by looking at the thread names, as reported by NetBeans: SwingWorker-pool-1-thread-1, where that poolis managed by SwingWorker.

您可以通过查看线程名称来识别这一事实,如 NetBeans: 报告的那样SwingWorker-pool-1-thread-1,该由 管理SwingWorker

If you want more control, you can also pass the SwingWorkerinstance to an Executor.

如果您想要更多控制,您还可以将SwingWorker实例传递给Executor.

Just check SwingWorkerand Executorjavadoc for further information.

只需检查SwingWorkerExecutorjavadoc 以获取更多信息。

Besides, SwingWorker.cancel()is not supposed to be called from doInBackground()but rather from another thread, generally the EDT, e.g. when user clicks a Cancelbutton in a progress dialog.

此外,SwingWorker.cancel()不应doInBackground()从另一个线程调用,而是从另一个线程调用,通常是 EDT,例如,当用户单击进度对话框中的取消按钮时。

回答by jzd

There is a cancel()method. Your code would have to pay attention to that. If it keeps running after an exception, it would appear that you code is ignoring an exception that it shouldn't be.

有一个cancel()方法。您的代码必须注意这一点。如果它在发生异常后继续运行,那么您的代码似乎忽略了它不应该存在的异常。

回答by Jeff Berkowitz

FYI for anyone passing through: when a SwingWorker is canceled, done() is called before doInBackground() returns.

仅供参考:当 SwingWorker 被取消时,done() 在 doInBackground() 返回之前被调用。

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514

Jeff

杰夫

回答by Joel Christophel

You need to add Thread.sleep(1)calls in your doInBackground() code every so often. In your sleep catch blocks, add return. I had the same problem, and this worked like a charm.

您需要Thread.sleep(1)经常在 doInBackground() 代码中添加调用。在您的 sleep catch 块中,添加return. 我遇到了同样的问题,这就像一个魅力。

Source: https://blogs.oracle.com/swinger/entry/swingworker_stop_that_train

来源:https: //blogs.oracle.com/swinger/entry/swingworker_stop_that_train

回答by pknoe3lh

Till The SwingWoker it fixed http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514Here a simple (tested) version with the basic (similar) functions then SwingWoker

直到 SwingWoker 它修复了http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514这里是一个简单的(经过测试的)版本,具有基本(类似)功能,然后是 SwingWoker

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tools;

import java.util.LinkedList;
import java.util.List;
import javax.swing.SwingUtilities;

/**
 *
 * @author patrick
 */
public abstract class MySwingWorker<R,P> {

    protected abstract R doInBackground() throws Exception;
    protected abstract void done(R rvalue, Exception ex, boolean canceled);
    protected void process(List<P> chunks){}
    protected void progress(int progress){}

    private boolean cancelled=false;
    private boolean done=false;
    private boolean started=false;
    final private Object syncprogress=new Object();
    boolean progressstate=false;
    private int progress=0;
    final private Object syncprocess=new Object();
    boolean processstate=false;
    private LinkedList<P> chunkes= new LinkedList<>();

    private Thread t= new Thread(new Runnable() {
        @Override
        public void run() {
            Exception exception=null;
            R rvalue=null;
            try {
                rvalue=doInBackground();
            } catch (Exception ex) {
                exception=ex;
            }

            //Done:
            synchronized(MySwingWorker.this)
            {
                done=true;
                final Exception cexception=exception;
                final R crvalue=rvalue;
                final boolean ccancelled=cancelled;

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        done(crvalue, cexception, ccancelled);
                    }
                });
            }

        }
    });    

    protected final void publish(P p)
    {
        if(!Thread.currentThread().equals(t))
            throw new UnsupportedOperationException("Must be called from worker Thread!");
        synchronized(syncprocess)
        {
            chunkes.add(p);
            if(!processstate)
            {
                processstate=true;
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        List<P> list;
                        synchronized(syncprocess)
                        {
                            MySwingWorker.this.processstate=false;
                            list=MySwingWorker.this.chunkes;
                            MySwingWorker.this.chunkes= new LinkedList<>();
                        }
                        process(list);
                    }
                });
            }
        }
    }

    protected final void setProgress(int progress)
    {
        if(!Thread.currentThread().equals(t))
            throw new UnsupportedOperationException("Must be called from worker Thread!");
        synchronized(syncprogress)
        {
            this.progress=progress;
            if(!progressstate)
            {
                progressstate=true;
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        int value;
                        //Acess Value
                        synchronized(syncprogress)
                        {
                            MySwingWorker.this.progressstate=false;
                            value=MySwingWorker.this.progress;
                        }
                        progress(value);
                    }
                });
            }
        }
    }

    public final synchronized void execute()
    {
        if(!started)
        {
            started=true;
            t.start();
        }
    }

    public final synchronized boolean isRunning()
    {
        return started && !done;
    }

    public final synchronized boolean isDone()
    {
        return done;
    }

    public final synchronized boolean isCancelled()
    {
        return cancelled;
    }

    public final synchronized void cancel()
    {
        if(started && !cancelled && !done)
        {
            cancelled=true;
            if(!Thread.currentThread().equals(t))
                t.interrupt();
        }
    }

}