目前我有两个SwingWorker线程在后台工作。如果发生异常,该方法将停止工作,但该线程仍然运行。
如果发生异常,如何停止执行并终止doInBackground()
的线程?
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;
}
}
我在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
答案 0 :(得分:10)
如jzd所述,有方法cancel(boolean mayInterruptIfRunning);为了exapmle
编辑:取消(真实);你必须(总是)哄骗异常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();
}
});
}
}
答案 1 :(得分:8)
默认情况下,SwingWorker
会重用工作线程,因此,即使doInBackground()
已返回,仍然可以看到执行方法的线程,这是完全正常的。
您可以通过查看NetBeans报告的线程名称来识别此事实:SwingWorker-pool-1-thread-1
,其中池由SwingWorker
管理。
如果您想要更多控制权,还可以将SwingWorker
个实例传递给Executor
。
只需查看SwingWorker和Executor javadoc即可获取更多信息。
此外,SwingWorker.cancel()
不应该从doInBackground()
调用,而是从另一个线程调用,通常是EDT,例如当用户在进度对话框中单击取消按钮时。
答案 2 :(得分:4)
有一种cancel()
方法。你的代码必须注意这一点。如果它在异常后继续运行,那么代码似乎忽略了它不应该出现的异常。
答案 3 :(得分:3)
对于任何通过的人来说:当取消SwingWorker时,在doInBackground()返回之前调用done()。
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514
杰夫
答案 4 :(得分:2)
您需要经常在doInBackground()代码中添加Thread.sleep(1)
次调用。在您的sleep catch块中,添加return
。我有同样的问题,这就像一个魅力。
来源: https://blogs.oracle.com/swinger/entry/swingworker_stop_that_train
答案 5 :(得分:0)
直到它修复的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();
}
}
}