【问题标题】:Is Java SwingWorker cancellation cooperative?Java SwingWorker 取消合作吗?
【发布时间】:2014-12-05 05:56:40
【问题描述】:

如果能帮助您理解这一点,我们将不胜感激。我的理解是取消 SwingWorker 线程是合作的。然而,这不是我所看到的。

下面的代码将停止 SwingWorker 线程,即使我没有可中断的操作。我不希望它以这种方式工作。请注意,我在 doStuff() 中专门放置了一个无限循环。当我在 main() 例程中取消时:

worker.cancel(true),

我在 done() 函数中结束,表明 doInBackground() 已退出(特别是在异常处理程序中)。即使没有可中断的操作,看起来线程也被杀死了。请注意,如果我更改为 worker.cancel(false),我会得到相同的效果。

class AWorker extends SwingWorker<String, Object> {
    void doStuff() {
        System.out.println("Entered doStuff");    
        while (true);
    }

    @Override
    public String doInBackground() {
        //System.out.println("doInBackground started");
        doStuff();
        return "hello";
    }

    @Override
    protected void done() {
        try {
            System.out.println("done() entered");
            String status = get();
            System.out.println("done(): get = " + status);
        } catch (Exception e) {
            System.out.println("done(): Exception: " + e);
        }
    }

    public static void main(String[] args) throws Exception {
        AWorker worker = new AWorker();
        worker.execute();

        Thread.sleep(5000);
        worker.cancel(true);

    }
}

我应该补充一点,我可以完全按照 Java 文档中的描述来完成这项工作,方法是协同进入在我取消或轮询 isCancelled() 时被中断的睡眠。只是想知道为什么它会像我在上面的代码 sn-p 中那样做。如果我冒险猜测一下,看起来当我调用 worker.cancel() 时没有刚才描述的协作机制,那么 done() 函数会立即被调用。

【问题讨论】:

    标签: java multithreading swingworker


    【解决方案1】:

    SwingWorker.done() 方法的文档似乎有点错误。它说 done() 在“doInBackground 方法完成后”被调用。但是,首先,当您取消 SwingWorker 时,显然也会调用 done(),即使您从未启动它。其次,如果您取消 SwingWorker,那么会立即调用 done(),即使 doInBackground() 方法还没有返回。这就是这里发生的事情。

    当 done() 被调用时,你的无限循环仍在运行。我确认使用以下代码将所有线程堆栈跟踪转储到控制台:

    static void dumpThreads() {
        for (java.util.Map.Entry<Thread,StackTraceElement[]> t : Thread.getAllStackTraces().entrySet()) {
            System.out.println(t.getKey() + ":");
            for (StackTraceElement e : t.getValue()) {
                System.out.println("    " + e);
            }
        }
    }
    

    我在 done() 中插入了对该方法的调用。线程堆栈跟踪之一显示无限循环当时仍然存在并且运行良好:

    Thread[SwingWorker-pool-1-thread-1,5,main]:
        AWorker.doStuff(AWorker.java:8)
        AWorker.doInBackground(AWorker.java:14)
        javax.swing.SwingWorker$1.call(SwingWorker.java:295)
        java.util.concurrent.FutureTask.run(FutureTask.java:266)
        javax.swing.SwingWorker.run(SwingWorker.java:334)
        java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        java.lang.Thread.run(Thread.java:744)
    

    但是,无限循环确实在不久之后被强制停止,不是由 SwingWorker 而是在程序结束时,因为当没有非守护线程运行(SwingWorker 线程是守护线程)并且没有创建窗口时,程序退出。这两件事的结合(狡猾的文档和自动退出)看起来取消 SwingWorker 正在神奇地停止任务,但事实并非如此。

    如果您从 main 方法打开一个窗口,这将阻止程序自动退出。然后,您会从系统任务管理器中看到该程序一直在运行(并在该无限循环中一直占用 CPU),直到您终止它。

    简而言之,是的,SwingWorker 取消合作的。

    【讨论】:

    • 非常有启发性的分析表明在 SwingWorker 被取消后 doInBackground 仍在实际执行。如果更新 Java 文档以更准确地反映所发生的情况,那就太好了。我尝试提交错误报告,但提交错误的 Oracle 流程非常可怕。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    • 2014-02-09
    • 2010-11-03
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 2011-09-01
    相关资源
    最近更新 更多