Java教程是针对JDK 8编写的。本页面中描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
请参阅Java语言变更,了解Java SE 9及后续版本中更新的语言功能的摘要。
请参阅JDK发布说明,了解所有JDK版本中的新功能、增强功能以及已删除或弃用选项的信息。
在进行后台任务时,往往有必要在任务仍在运行时提供中间结果。任务可以通过调用SwingWorker.publish
来实现。此方法接受可变数量的参数。每个参数的类型必须与SwingWorker
的第二个类型参数指定的类型相同。
为了收集publish
提供的结果,可以重写SwingWorker.process
方法。该方法将从事件分派线程中调用。通常,多次调用publish
的结果将累积为单次调用process
。
让我们看一下
示例如何使用Flipper.java
publish
提供中间结果。点击启动按钮使用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
中间结果演示。