done()
SwingWorker:
方法的Javadoc
在doInBackground方法之后在Event Dispatch Thread上执行 完了。
我发现在取消工人的情况下并非如此
在每种情况下都会调用Done
(正常终止或取消),但当cancelled
未加入到EDT时,就像正常终止时一样。
在取消done
的情况下调用SwingWorker
时是否会有更精确的分析?
澄清:
关于如何cancel
一个SwingWorker
,这个问题不。这里假设SwingWorker
以正确的方式被取消
不关于线程在应该完成时仍然有效。
答案 0 :(得分:19)
通过
取消线程时myWorkerThread.cancel(true/false);
完成方法(非常令人惊讶地)由cancel方法本身调用。
您可能会发生什么,但实际上并非如此:
- 你打电话取消(或者是否带有mayInterrupt)
- 取消设置线程取消
- doInBackground退出
- 完成称为*
(*完成排队到EDT,这意味着,如果EDT正忙,它会在EDT完成之后发生)
实际发生了什么:
- 你打电话取消(或者是否带有mayInterrupt)
- 取消设置线程取消
- 完成作为取消代码*
的一部分调用
- 当doInBackground完成循环时,它将退出
(*完成没有排入EDT,但调用取消调用,因此它对EDT有非常直接的影响,通常是GUI)
我提供了一个证明这一点的简单例子。
复制,粘贴和运行。
1.我在done中生成了一个运行时异常。堆栈线程显示由cancel调用done。
2.在取消后大约4秒后,你将从doInBackground中收到一个问候语,这可以证明在线程退出之前调用了done。
import java.awt.EventQueue;
import javax.swing.SwingWorker;
public class SwingWorker05 {
public static void main(String [] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
W w = new W();
w.execute();
Thread.sleep(1000);
try{w.cancel(false);}catch (RuntimeException rte) {
rte.printStackTrace();
}
Thread.sleep(6000);
} catch (InterruptedException ignored_in_testing) {}
}
});
}
public static class W extends SwingWorker <Void, Void> {
@Override
protected Void doInBackground() throws Exception {
while (!isCancelled()) {
Thread.sleep(5000);
}
System.out.println("I'm still alive");
return null;
}
@Override
protected void done() {throw new RuntimeException("I want to produce a stack trace!");}
}
}
答案 1 :(得分:6)
done()
,工作人员被取消或正常结束。然而,有些情况下doInBackground
仍然在运行并且done
方法已经被调用(无论线程是否已经完成,这都在cancel()
内部完成)。这里有一个简单的例子:
public static void main(String[] args) throws AWTException {
SwingWorker<Void, Void> sw = new SwingWorker<Void, Void>() {
protected Void doInBackground() throws Exception {
System.out.println("start");
Thread.sleep(2000);
System.out.println("end");
return null;
}
protected void done() {
System.out.println("done " + isCancelled());
}
};
sw.execute();
try {
Thread.sleep(1000);
sw.cancel(false);
Thread.sleep(10000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
因此可能会在done
完成之前调用doInBackground
。
答案 2 :(得分:1)
某些事情是可能的,其他可能是错觉
非常好的outPut
run:
***removed***
java.lang.RuntimeException: I want to produce a stack trace!
at help.SwingWorker05$W.done(SwingWorker05.java:71)
at javax.swing.SwingWorker$5.run(SwingWorker.java:717)
at javax.swing.SwingWorker.doneEDT(SwingWorker.java:721)
at javax.swing.SwingWorker.access$100(SwingWorker.java:207)
at javax.swing.SwingWorker$2.done(SwingWorker.java:284)
at java.util.concurrent.FutureTask$Sync.innerCancel(FutureTask.java:293)
at java.util.concurrent.FutureTask.cancel(FutureTask.java:76)
at javax.swing.SwingWorker.cancel(SwingWorker.java:526)
at help.SwingWorker05$1.run(SwingWorker05.java:25)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
I'm still alive
Thread Status with Name :SwingWorker1, SwingWorker Status is STARTED
SwingWorker by tutorial's background process has completed
Thread Status with Name :SwingWorker1, SwingWorker Status is DONE
Thread Status with Name :look here what's possible with SwingWorker, SwingWorker Status is STARTED
BUILD SUCCESSFUL (total time: 10 seconds)
这
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.SwingWorker;
public class SwingWorker05 {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
W w = new W();
w.addPropertyChangeListener(
new SwingWorkerCompletionWaiter("look here what's possible with SwingWorker"));
w.execute();
Thread.sleep(1000);
try {
w.cancel(false);
} catch (RuntimeException rte) {
rte.printStackTrace();
}
Thread.sleep(6000);
} catch (InterruptedException ignored_in_testing) {
}
}
});
final MySwingWorker mySW = new MySwingWorker();
mySW.addPropertyChangeListener(new SwingWorkerCompletionWaiter("SwingWorker1"));
mySW.execute();
}
private static class MySwingWorker extends SwingWorker<Void, Void> {
private static final long SLEEP_TIME = 250;
@Override
protected Void doInBackground() throws Exception {
Thread.sleep(SLEEP_TIME);
return null;
}
@Override
protected void done() {
System.out.println("SwingWorker by tutorial's background process has completed");
}
}
public static class W extends SwingWorker {
@Override
protected Object doInBackground() throws Exception {
while (!isCancelled()) {
Thread.sleep(5000);
}
System.out.println("I'm still alive");
return null;
}
@Override
protected void done() {
System.out.println("***remove***");
throw new RuntimeException("I want to produce a stack trace!");
}
}
private static class SwingWorkerCompletionWaiter implements PropertyChangeListener {
private String str;
SwingWorkerCompletionWaiter(String str) {
this.str = str;
}
@Override
public void propertyChange(PropertyChangeEvent event) {
if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) {
System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue());
} else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.PENDING == event.getNewValue()) {
System.out.println("Thread Status with Mame :" + str + ", SwingWorker Status is " + event.getNewValue());
} else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.STARTED == event.getNewValue()) {
System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue());
} else {
System.out.println("Thread Status with Name :" + str + ", Something wrong happends ");
}
}
}
}
答案 3 :(得分:1)
直到修复SwingWorker http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514 这是一个简单(经过测试)的版本,其基本(类似)函数然后是SwingWorker
/*
* 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();
}
}
}
答案 4 :(得分:0)
来自Java文档: 取消(布尔值mayInterruptIfRunning) “mayInterruptIfRunning - 如果执行此任务的线程应该被中断,则为true;否则,允许正在进行的任务完成”
如果您调用cancel(true)而不是取消(false),这似乎与您期望的一样。
我没有看到使用EventQueue.isDispatchThread()
取消了EDT的完成()答案 5 :(得分:0)
如果您使用return Void:... @ Override public Void doInBackground(){...
当doInBackground()完成时,调用done()。
如果你不使用return Void:... @ Override public boolean doInBackground(){...
完成()被忽略,你知道已经完成,因为你有回报。