【问题标题】:SwingWorker's done method executes even before doInBackground is finished, randomlySwingWorker 的 done 方法甚至在 doInBackground 完成之前随机执行
【发布时间】:2013-09-13 04:56:32
【问题描述】:

我有一段JFrame 代码,它在关闭时停止SwingWorker

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
import javax.swing.WindowConstants;

/**
 *
 * @author yccheok
 */
public class JavaApplication11 extends JFrame {

    public JavaApplication11() {
        this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

        final Task task = new Task();
        task.execute();
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosed(WindowEvent e) {
                if (task != null) {
                    task.cancel(true);
                }
            }           
        }); 
    }

    public class Task extends SwingWorker<Void, Void> {

        @Override
        protected Void doInBackground() {
            for (int i = 0; i < 1000; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    System.out.println("interrupted in doInBackground");
                    break;
                }
                System.out.println("-> " + i);
            }
            return null;
        }

        @Override
        public void done() {
            System.out.println("DONE!!!");
        }        
    }
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new JavaApplication11().setVisible(true);
    }
}

但是,随机地,当我关闭JFrame 时,我意识到SwingWorkerdone 方法在doInBackground 完成之前执行。 (你需要多次执行上面的JFrame才能产生问题)

-> 0
-> 1
-> 2
-> 3
-> 4
DONE!!!
interrupted in doInBackground

我可以知道为什么会这样吗?

【问题讨论】:

  • 这可能是标准输出竞争条件的演示
  • 如果 MadProgrammer 是正确的,包括在您的 sysout 调用上的时间戳应该会显示它... 跟踪此问题的一种策略是在您的 IDE 中包含 Swingworker 的源代码,并在完成和doInBackgroun的最后一步......只是一个想法......
  • 难道不是因为在 EDT 上调用了 done 并且 doInBackground 在自己的线程上运行,所以它们不必一个接一个地来?并自动取消呼叫完成。另外,只需在打印之前在 catch 块中添加另一个 sleep ,您每次都会看到它。
  • IF 我明白发生了什么。支持SwingWorkerFuture 被取消,done 方法在同一Thread 的上下文中被调用。这意味着done可能在doInBackground方法正在运行的Thread被调度运行并检测到中断之前执行...

标签: java multithreading swing swingworker


【解决方案1】:

根据 Howard 的评论,http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6826514 表明这可能是一个错误。

我也遇到过这种情况。我倾向于将清理放在doInBackground 中,如果它依赖于顺序,并且只使用done 进行异常处理。

@Override
protected Void doInBackground() {
    try {
        // ...
    } finally {
        // some cleanup inside 'doInBackground'
        if (isCancelled()) {
            // ...
        } else {
            // ...
        }
    }
    return (Void) null;
}
@Override
protected void done() {
    try {
        get();
    } catch (CancellationException x) {
        // ...
    } catch (InterruptedException x) {
        // ...
    } catch (ExecutionException x) {
        // ...
    }
}

(如果您需要从doInBackground 更新GUI,请记住使用invokeLater。)

就我而言,我有这样的事情:

  • doInBackground 执行“打开文件”例程,定期创建 Swing 组件并将它们添加到 GUI。
  • 取消时(通过带有 Cancel 按钮的进度条对话框),done 将删除在doInBackground 期间创建的所有组件。

有时这些操作会重叠,doInBackground 会在done 执行擦除后继续创建组件。对用户来说,按下 Cancel 似乎只是偶尔不起作用,除了调试显示 done 正在被调用。除了SwingWorker的这种行为,没有其他解释。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-17
    • 2016-10-07
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多