为什么SwingWorkers需要发布?

时间:2016-02-25 19:25:56

标签: java multithreading

我正在尝试在后台运行一个进程三秒钟,并让它可以取消。现在我有一个例子,增加一个int,直到三秒钟或工人被取消。

import java.util.List;

import javax.swing.SwingWorker;

public class Example {

    public static void main(String[] args) throws InterruptedException {
        ExampleWorker worker = new ExampleWorker();
        worker.execute();
        Thread.sleep(10);
        //worker.cancel(false);
    }

}

class ExampleWorker extends SwingWorker<String, Integer> {

    private int n = 0;
    private long startTime;
    private boolean cancelled = false;

    @Override
    protected String doInBackground() throws Exception {
        System.out.println("doInBackground()");
        startTime = System.currentTimeMillis();
        while (!cancelled && System.currentTimeMillis() - startTime < 3000) {
            publish(n++);
        }
        return "What is this used for?";
    }

    @Override
    protected void done() {
        cancelled = true;
        System.out.println(n);
    }

}

我曾经有一个打印出来的流程方法。我删除了它,但我保留了publish(n++)。一切正常。但是当我用publish(n++)替换n++时,如果我不取消工作人员,则不会打印出任何内容。为什么删除发布会产生此问题?

1 个答案:

答案 0 :(得分:1)

您应该查看Worker Threads and SwingWorkerJavaDocs for SwingWorker,它们会为您提供更多信息。

基本上,publish将值放在队列中,该队列将在EDT的上下文中传递给publish方法。这用于允许信息从worker的后台线程传递到EDT,其中值可用于安全地更新UI。

应该使用done方法来获取后台操作的结果(假设它有一个),可以使用get方法检索该方法,该方法将返回从doInBackground方法或生成的异常

import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.SwingWorker;

public class Test {

    public static void main(String[] args) throws InterruptedException {
        ExampleWorker worker = new ExampleWorker();
        worker.execute();
        Thread.sleep(100);
        try {
            System.out.println(">> " + worker.get());
        } catch (ExecutionException ex) {
            ex.printStackTrace();
        }
    }

    public static class ExampleWorker extends SwingWorker<String, Integer> {

        private int n = 0;
        private long startTime;

        @Override
        protected String doInBackground() throws Exception {
            System.out.println("doInBackground()");
            startTime = System.currentTimeMillis();
            while (System.currentTimeMillis() - startTime < 3000) {
                publish(n++);
                Thread.yield();
            }
            return "What is this used for?";
        }

        @Override
        protected void process(List<Integer> chunks) {
            for (int value : chunks) {
                System.out.println(value);
            }
        }

        @Override
        protected void done() {
            System.out.println("Done: " + n);
        }

    }

}

更新了更直接的示例...

  

我没有处理方法,因为我不想在后台操作完成之前将信息传递给EDT。

然后请勿使用publish / process,使用done并返回您要从doInBackground

中检索的值
  

我仍然在我的代码中发布的唯一原因是,如果我没有取消该过程,它在没有它的情况下无法工作。

似乎对我有用,SwingWorker已经拥有取消状态

  

并且没有()阻止EDT上的所有内容?我不希望这样,因为它阻止我的GUI工作

是的,当工人正在跑步时,如果工人已经完成,它将立即返回。在您的示例中,由于缺少任何UI以防止JVM退出,这是一种阻止JVM退出的方法

这意味着您可以使用done通常在doInBackground返回后和/或PropertyChangeListener内调用的import java.awt.EventQueue; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFrame; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class Test { public static void main(String[] args) throws InterruptedException { new Test(); } public Test() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { ex.printStackTrace(); } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(new JLabel("Waiting")); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); ExampleWorker worker = new ExampleWorker(); worker.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("state".equals(evt.getPropertyName())) { ExampleWorker worker = (ExampleWorker) evt.getSource(); switch (worker.getState()) { case DONE: { try { System.out.println("PropertyChange: " + worker.get()); } catch (InterruptedException | ExecutionException ex) { ex.printStackTrace(); } frame.dispose(); } break; } } } }); worker.execute(); } }); } public static class ExampleWorker extends SwingWorker<Integer, Integer> { private int n = 0; private long startTime; @Override protected Integer doInBackground() throws Exception { System.out.println("doInBackground()"); startTime = System.currentTimeMillis(); while (System.currentTimeMillis() - startTime < 3000) { n++; Thread.yield(); } return n; } @Override protected void process(List<Integer> chunks) { for (int value : chunks) { System.out.println(value); } } @Override protected void done() { try { System.out.println("Done: " + get()); } catch (InterruptedException | ExecutionException ex) { ex.printStackTrace(); } } } } ,具体取决于您的需求

DelegateProxyType