Java教程是针对JDK 8编写的。本页面中描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
请参阅Java语言变更,了解Java SE 9及后续版本中更新的语言功能的摘要。
请参阅JDK发布说明,了解所有JDK版本中的新功能、增强功能以及已删除或弃用选项的信息。
在进行后台任务时,往往有必要在任务仍在运行时提供中间结果。任务可以通过调用SwingWorker.publish来实现。此方法接受可变数量的参数。每个参数的类型必须与SwingWorker的第二个类型参数指定的类型相同。
为了收集publish提供的结果,可以重写SwingWorker.process方法。该方法将从事件分派线程中调用。通常,多次调用publish的结果将累积为单次调用process。
让我们看一下示例如何使用Flipper.javapublish提供中间结果。点击启动按钮使用Java™ Web Start运行Flipper(下载JDK 7或更高版本)。或者,要自己编译和运行示例,请参考示例索引。
该程序通过在后台任务中生成一系列随机的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 方法实际上符合其 规范中定义的“线程安全”。这意味着我们可以在工作线程中直接设置文本字段,而不需要使用 publish 和 process。我们选择忽略这一事实,以便提供一个简单的 SwingWorker 中间结果演示。