SwingWorker:什么时候被称为done方法?

SwingWorker:done()方法的Javadoc SwingWorker:

在doInBackground方法完成后在Event Dispatch Thread上执行。

我已经找到了在取消工人的情况下不是这样的线索。
在每种情况下都会调用Done (正常终止或取消)但在cancelled不会排入 EDT,因为正常终止时会发生这种情况。

在取消SwingWorker的情况下调用done时是否有更精确的分析?

澄清:这个问题在于如何cancel SwingWorker 。 这里假设SwingWorker以正确的方式被取消。
而且当它们应该完成时,它不是关于线程仍在工作。

通过线程取消线程时

 myWorkerThread.cancel(true/false); 

完成方法(非常令人惊讶地)由cancel方法本身调用。

你可能会发生什么,但实际上并没有:
– 你打电话取消(与mayInterrupt一起或不)
– 取消设置线程取消
– doInBackground退出
– 完成被称为*
(*完成后排队到EDT,这意味着,如果EDT很忙,它会在EDT完成之后发生)

实际上会发生什么:
– 你打电话取消(与mayInterrupt一起或不)
– 取消设置线程取消
– 完成作为取消代码的一部分调用*
– doInBackground将在完成循环后退出
(*完成没有排入EDT,但调用取消调用,因此它对EDT有非常直接的影响,通常是GUI)

我提供了一个certificate这一点的简单例子。
复制,粘贴和运行。
1.我在done中生成了一个运行时exception。 堆栈线程显示由cancel调用done。
2.在取消后大约4秒后,你将从doInBackground中收到一个问候语,这可以certificate在线程退出之前调用了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  { @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!");} } } 

在任何情况下都会调用done() ,工作人员被取消或正常完成。 然而,有些情况下doInBackground仍然在运行并且已经调用了done方法cancel()无论线程是否已经完成,这都在cancel()完成。 这里有一个简单的例子:

 public static void main(String[] args) throws AWTException { SwingWorker sw = new SwingWorker() { 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(); } 

因此,可能是在doInBackground完成之前doInBackground done的情况。

有些事情是可能的,其他可能是错觉

非常好的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 { 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 "); } } } } 

在修复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 { protected abstract R doInBackground() throws Exception; protected abstract void done(R rvalue, Exception ex, boolean canceled); protected void process(List

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

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

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

来自Java文档:cancel(boolean mayInterruptIfRunning)“mayInterruptIfRunning – 如果执行此任务的线程应该被中断,则为true;否则,允许正在进行的任务完成”

如果你调用cancel(true)而不是cancel(false),它似乎表现得像你期望的那样。

我没有看到使用EventQueue.isDispatchThread()取消了EDT的完成()

如果你使用return Void:… @ Override public Void doInBackground(){…

doInBackground()完成后调用done()。

如果你不使用return Void:… @ Override public boolean doInBackground(){…

完成()被忽略,你知道已经完成,因为你有你的回报。