文档

Java™ 教程
隐藏目录
具有中间结果的任务
路径: 使用Swing创建GUI
课程: Swing中的并发性
章节: 工作线程和SwingWorker

具有中间结果的任务

在进行后台任务时,往往有必要在任务仍在运行时提供中间结果。任务可以通过调用SwingWorker.publish来实现。此方法接受可变数量的参数。每个参数的类型必须与SwingWorker的第二个类型参数指定的类型相同。

为了收集publish提供的结果,可以重写SwingWorker.process方法。该方法将从事件分派线程中调用。通常,多次调用publish的结果将累积为单次调用process

让我们看一下Flipper.java示例如何使用publish提供中间结果。点击启动按钮使用Java™ Web Start运行Flipper下载JDK 7或更高版本)。或者,要自己编译和运行示例,请参考示例索引

启动Flipper示例

该程序通过在后台任务中生成一系列随机的boolean值来测试java.util.Random的公平性。这相当于抛硬币;因此命名为Flipper。为了报告其结果,后台任务使用FlipPair类型的对象。

private static class FlipPair {
    private final long heads, total;
    FlipPair(long heads, long total) {
        this.heads = heads;
        this.total = total;
    }
}

heads字段是随机值为true的次数;total字段是随机值的总数。

后台任务由FlipTask的实例表示:

private class FlipTask extends SwingWorker<Void, FlipPair> {

由于任务不返回最终结果,第一个类型参数是什么并不重要;Void被用作占位符。任务在每次“抛硬币”后调用publish

@Override
protected Void doInBackground() {
    long heads = 0;
    long total = 0;
    Random random = new Random();
    while (!isCancelled()) {
        total++;
        if (random.nextBoolean()) {
            heads++;
        }
        publish(new FlipPair(heads, total));
    }
    return null;
}

(下一节将讨论 isCancelled 方法。) 由于 publish 方法被频繁调用,所以在事件分派线程中调用 process 方法之前,很可能会积累很多 FlipPair 值;process 方法只关心每次报告的最后一个值,并用它来更新GUI:

protected void process(List<FlipPair> pairs) {
    FlipPair pair = pairs.get(pairs.size() - 1);
    headsText.setText(String.format("%d", pair.heads));
    totalText.setText(String.format("%d", pair.total));
    devText.setText(String.format("%.10g", 
            ((double) pair.heads)/((double) pair.total) - 0.5));
}

如果 Random 是公平的,那么在 Flipper 运行时,devText 中显示的值应该越来越接近0。


注意: Flipper 中使用的 setText 方法实际上符合其 规范中定义的“线程安全”。这意味着我们可以在工作线程中直接设置文本字段,而不需要使用 publishprocess。我们选择忽略这一事实,以便提供一个简单的 SwingWorker 中间结果演示。

上一页: 简单后台任务
下一页: 取消后台任务