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

Ago*_*noX 19 java swing swingworker cancellation

Javadoc的done()方法SwingWorker:

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

我已经找到了在取消工人的情况下不是这样的线索.
Done在每种情况下都会被调用(正常终止或取消),但是当cancelled没有排入 EDT时,就像正常终止时那样.

doneSwingWorker取消a的情况下调用时是否有一些更精确的分析?

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

Ago*_*noX 19

通过线程取消线程时

myWorkerThread.cancel(true/false);
Run Code Online (Sandbox Code Playgroud)

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

您可能会发生什么,但实际上不会:
- 您调用取消(使用mayInterrupt或不使用)
- 取消设置线程取消
- doInBackground退出
- 完成被称为*
(*已完成排队到EDT ,这意味着,如果EDT很忙,它会在EDT完成之后发生.

实际上会发生什么:
- 你调用cancel(无论是否使用mayInter)
- 取消设置线程取消
- 完成作为取消代码*的一部分调用
- 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!");}

}

}
Run Code Online (Sandbox Code Playgroud)

  • 因此,甚至可能发生在"完成"之后发布/处理结果. (3认同)
  • +1与我大约在同一时间得到的相同(惊人)结果;-) (2认同)
  • 这已被Oracle接受为错误:http://bugs.sun.com/bugdatabase/view_bug.do?video_id = 6826514 (2认同)
  • 该错误报告尚未更新,但在Java 7中调用`#cancel()`不会调用`#done()`(Oracle JDK) (2认同)
  • 抱歉,@searchengine27,但事实并非如此。立即查看 Java 8 JRE 源代码;`SwingWorker#cancel()` 调用 `FutureTask#cancel()`,**如果它没有立即返回 false** 调用私有辅助方法 `finishCompletion()`,该方法无条件调用 `FutureTask#done()`。并且 SwingWorker 的 FutureTask 的匿名子类覆盖了 `done()` 以调用它自己的私有 `SwingWorker#doneEDT()`,它无条件地在 EDT 上调用或排队它自己的 `done()`。 (2认同)

How*_*ard 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();
    }
Run Code Online (Sandbox Code Playgroud)

因此,可以done是在doInBackground完成之前调用的情况.