java SwingWorker:什么时候调用完成方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6204141/
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
SwingWorker: when exactly is called done method?
提问by AgostinoX
Javadoc of the done()
method of SwingWorker:
done()
方法的JavadocSwingWorker:
Executed on the Event Dispatch Thread after the doInBackground method is finished.
doInBackground 方法完成后在事件调度线程上执行。
I've clues that it is not true in the case of canceled worker.Done
is called in each case (normal termination or cancellation) but when cancelled
it is not enqueuedto the EDT, as it happens for normal termination.
我有线索表明,在取消工人的情况下,情况并非如此。Done
在每种情况下(正常终止或取消)都会调用,但是当cancelled
它没有排队到 EDT 时,就像正常终止一样。
Is there some more precise analisis on when done
is called in the case that a SwingWorker
is cancelled?
done
在SwingWorker
取消a 的情况下,是否有更精确的分析何时调用?
Clarification:
this question is NOTon how to cancel
a SwingWorker
. Here it is assumed that the SwingWorker
is cancelled in the right way.
And it is NOTabout thread still working when they are supposed to be finished.
澄清:这个问题是不是就如何cancel
一个SwingWorker
。这里假设SwingWorker
以正确的方式取消。
它是不是什么时候他们应该完成的线程仍在工作。
采纳答案by AgostinoX
When a thread is cancelled via
当一个线程被取消时
myWorkerThread.cancel(true/false);
the done method is (quite surprisingly) called by the cancel method itself.
done 方法(非常令人惊讶)由取消方法本身调用。
What you may expect to happen, but actually DOESN'T:
- you call cancel (either with mayInterrupt or not)
- cancel set up the thread cancellation
- the doInBackground exits
- the done is called*
(* the done is enqueuedto the EDT, that means, if EDT is busy it happens AFTER the EDT has finished what it is doing)
您可能期望发生的事情,但实际上并没有:
- 您调用取消(无论是否使用 mayInterrupt)
- 取消设置线程取消
- doInBackground 退出
- 调用完成*
(* 完成排队到 EDT ,这意味着,如果 EDT 很忙,它会在 EDT 完成它正在做的事情之后发生)
What actually DOES happen:
- you call cancel (either with mayInterrupt or not)
- cancel set up the thread cancellation
- the done is called as part of cancel code*
- the doInBackground will exit when it will have finished its loop
(*the done isn't enqueued to the EDT, but called into the cancel call and so it has a very immediate effect on EDT, that often is the GUI)
实际发生了什么:
- 您调用取消(无论是否使用 mayInterrupt)
- 取消设置线程取消
- done 被称为取消代码的一部分*
- doInBackground 将在完成其循环时退出
(*完成没有排队到 EDT,而是被调用到取消调用中,因此它对 EDT 有非常直接的影响,通常是 GUI)
I provide a simple example that proves this.
Copy, paste and run.
1. I generate a runtime exception inside done. The stack thread shows that done is called by cancel.
2. About after 4 seconds after cancelation, you'll recive a greeting from the doInBackground, that fhurterly proves that done is called before the thread exiting.
我提供了一个简单的例子来证明这一点。
复制、粘贴和运行。
1.我在done里面生成了一个运行时异常。堆栈线程显示 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!");}
}
}
回答by Howard
done()
is called in any case, wether the worker is cancelled or it finishes normally. Nevertheless there are cases where the doInBackground
is still running and the done
method is called already (this is done inside cancel()
no matter if the thread already finished). A simple example can be found here:
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();
}
Thus it can be the case that done
is called before doInBackground
finishes.
因此,它可能done
是在doInBackground
完成之前调用的情况。
回答by mKorbel
something is possible, other could be illusion
有些事情是可能的,其他的可能是错觉
really nice 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.run(SwingWorker.java:717)
at javax.swing.SwingWorker.doneEDT(SwingWorker.java:721)
at javax.swing.SwingWorker.access0(SwingWorker.java:207)
at javax.swing.SwingWorker.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.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)
from
从
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 ");
}
}
}
}
回答by pknoe3lh
Until the SwingWorker is fixed http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514Here a simple (tested) version with the basic (similar) functions then SwingWorker
直到 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();
}
}
}
回答by IvanVar
IF you use return Void: ...@Override public VoiddoInBackground(){...
如果你使用 return Void: ...@Override public VoiddoInBackground(){...
done() is invoked when doInBackground() has finished.
done() 在 doInBackground() 完成时被调用。
IF you don't use return Void: ...@Override public booleandoInBackground(){...
如果你不使用 return Void: ...@Override public booleandoInBackground(){...
done() is ignored and you know have finished cause you have your return.
done() 被忽略,你知道已经完成,因为你有你的回报。
回答by user1610348
From the Java docs: cancel(boolean mayInterruptIfRunning) "mayInterruptIfRunning - true if the thread executing this task should be interrupted; otherwise, in-progress tasks are allowed to complete"
来自 Java 文档:cancel(boolean mayInterruptIfRunning) "mayInterruptIfRunning - 如果执行此任务的线程应该被中断,则为 true;否则,允许进行中的任务完成"
If you call cancel(true) instead of cancel(false) that seems to behave as you are expecting.
如果您调用cancel(true) 而不是cancel(false),这似乎表现得如您所愿。
I have not seen done() called off the EDT using EventQueue.isDispatchThread()
我还没有看到 done() 使用 EventQueue.isDispatchThread() 取消了 EDT