- 类型参数:
-
T- 由此SwingWorker的doInBackground和get方法返回的结果类型 -
V- 由此SwingWorker的publish和process方法用于传递中间结果的类型
- 所有实现的接口:
-
Runnable,Future<T>,RunnableFuture<T>
SwingWorker的线程的确切策略是未指定的,不应依赖于它。
在使用Swing编写多线程应用程序时,有两个约束需要牢记:(有关更多详细信息,请参阅Swing中的并发性):
- 耗时任务不应在事件分派线程上运行。否则应用程序会变得无响应。
- Swing组件只能在事件分派线程上访问。
这些约束意味着具有耗时计算需求的GUI应用程序至少需要两个线程:1) 用于执行耗时任务的线程,2) 用于所有GUI相关活动的事件分派线程(EDT)。这涉及跨线程通信,可能难以实现。
SwingWorker设计用于需要在后台线程中运行长时间运行任务并在完成时或处理过程中向UI提供更新的情况。 SwingWorker的子类必须实现doInBackground()方法来执行后台计算。
工作流程
SwingWorker的生命周期涉及三个线程:
-
当前线程:在此线程上调用
execute()方法。它安排SwingWorker在工作线程上执行并立即返回。可以使用get方法等待SwingWorker完成。 -
工作线程:在此线程上调用
doInBackground()方法。这是所有后台活动应发生的地方。要通知PropertyChangeListeners有关绑定属性更改,请使用firePropertyChange和getPropertyChangeSupport()方法。默认情况下,有两个可用的绑定属性:state和progress。 -
事件分派线程:所有与Swing相关的活动发生在此线程上。
SwingWorker调用process和done方法,并在此线程上通知任何PropertyChangeListeners。
通常,当前线程是事件分派线程。
在工作线程上调用doInBackground方法之前,SwingWorker会通知任何PropertyChangeListeners有关state属性更改为StateValue.STARTED。在doInBackground方法完成后,将执行done方法。然后,SwingWorker会通知任何PropertyChangeListeners有关state属性更改为StateValue.DONE。
SwingWorker仅设计为执行一次。多次执行SwingWorker不会导致调用doInBackground方法两次。
示例用法
以下示例说明了最简单的用法。在后台进行一些处理,完成后更新Swing组件。
假设我们想找到"生命的意义"并在JLabel中显示结果。
final JLabel label;
class MeaningOfLifeFinder extends SwingWorker<String, Object> {
@Override
public String doInBackground() {
return findTheMeaningOfLife();
}
@Override
protected void done() {
try {
label.setText(get());
} catch (Exception ignore) {
}
}
}
(new MeaningOfLifeFinder()).execute();
下一个示例适用于希望在事件分派线程上处理数据的情况。
现在我们想找到前N个质数并在JTextArea中显示结果。在计算过程中,我们希望在JProgressBar中更新进度。最后,我们还想将质数打印到System.out。
class PrimeNumbersTask extends
SwingWorker<List<Integer>, Integer> {
PrimeNumbersTask(JTextArea textArea, int numbersToFind) {
//初始化
}
@Override
public List<Integer> doInBackground() {
while (! enough && ! isCancelled()) {
number = nextPrimeNumber();
publish(number);
setProgress(100 * numbers.size() / numbersToFind);
}
}
return numbers;
}
@Override
protected void process(List<Integer> chunks) {
for (int number : chunks) {
textArea.append(number + "\n");
}
}
}
JTextArea textArea = new JTextArea();
final JProgressBar progressBar = new JProgressBar(0, 100);
PrimeNumbersTask task = new PrimeNumbersTask(textArea, N);
task.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer)evt.getNewValue());
}
}
});
task.execute();
System.out.println(task.get()); //打印我们得到的所有质数
因为SwingWorker实现了Runnable,所以可以将SwingWorker提交给Executor以执行。
- 自1.6版本起:
- 1.6
-
Nested Class Summary
Nested ClassesNested classes/interfaces declared in interface java.util.concurrent.Future
Future.State -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionfinal void向侦听器列表添加PropertyChangeListener。final booleancancel(boolean mayInterruptIfRunning) 尝试取消执行此任务。protected abstract T计算结果,如果无法执行则抛出异常。protected voiddone()在doInBackground方法完成后在事件分派线程上执行。final voidexecute()将此SwingWorker安排在工作线程上执行。final voidfirePropertyChange(String propertyName, Object oldValue, Object newValue) 向任何已注册的侦听器报告绑定属性更新。final Tget()如有必要等待计算完成,然后检索其结果。final T如有必要等待最多指定时间以完成计算,然后检索其结果(如果可用)。final int返回progress绑定属性。final PropertyChangeSupport返回此SwingWorker的PropertyChangeSupport。final SwingWorker.StateValuegetState()返回SwingWorker状态绑定属性。final boolean如果此任务在正常完成之前被取消,则返回true。final booleanisDone()如果此任务已完成,则返回true。protected void在事件分派线程上异步接收来自publish方法的数据块。protected final void将数据块发送到process(java.util.List<V>)方法。final void从侦听器列表中删除PropertyChangeListener。final voidrun()将此Future设置为计算的结果,除非已取消。protected final voidsetProgress(int progress) 设置progress绑定属性。Methods declared in class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, waitMethods declared in interface java.util.concurrent.Future
exceptionNow, resultNow, state
-
Constructor Details
-
SwingWorker
public SwingWorker()构造此SwingWorker。
-
-
Method Details
-
doInBackground
计算结果,如果无法执行则抛出异常。请注意,此方法仅执行一次。
注意:此方法在后台线程中执行。
- 返回:
- 计算的结果
- 抛出:
-
Exception- 如果无法计算结果
-
run
public final void run()将此Future设置为计算的结果,除非已取消。- 指定者:
-
run在接口Runnable中 - 指定者:
-
run在接口RunnableFuture<T>中
-
publish
将数据块发送到process(java.util.List<V>)方法。此方法应从doInBackground方法内部使用,以便在process方法中的事件分派线程上交付中间结果进行处理。由于
process方法在事件分派线程上异步调用,可能会在process方法执行之前发生多次对publish方法的调用。出于性能考虑,所有这些调用都会合并为一个带有连接参数的调用。例如:
publish("1"); publish("2", "3"); publish("4", "5", "6");可能导致:process("1", "2", "3", "4", "5", "6")示例用法。此代码片段加载一些表格数据并使用它更新
DefaultTableModel。请注意,可以安全地从process方法内部对tableModel进行变异,因为它在事件分派线程上调用。class TableSwingWorker extends SwingWorker<DefaultTableModel, Object[]> { private final DefaultTableModel tableModel; public TableSwingWorker(DefaultTableModel tableModel) { this.tableModel = tableModel; }@Overrideprotected DefaultTableModel doInBackground() throws Exception { for (Object[] row = loadData(); ! isCancelled() && row != null; row = loadData()) { publish((Object[]) row); } return tableModel; }@Overrideprotected void process(List<Object[]> chunks) { for (Object[] row : chunks) { tableModel.addRow(row); } } }- 参数:
-
chunks- 要处理的中间结果 - 参见:
-
process
从publish方法异步地在事件分派线程上接收数据块。请参阅
publish(V...)方法以获取更多详细信息。- 参数:
-
chunks- 要处理的中间结果 - 参见:
-
done
protected void done()在doInBackground方法完成后在事件分派线程上执行。默认实现不执行任何操作。子类可以重写此方法,在事件分派线程上执行完成操作。请注意,您可以在此方法的实现内部查询状态,以确定此任务的结果或此任务是否已被取消。- 参见:
-
setProgress
protected final void setProgress(int progress) 设置progress绑定属性。该值应为0到100。由于
PropertyChangeListener在事件分派线程上异步通知,可能会在调用setProgress方法之前发生多次调用setProgress方法。出于性能考虑,所有这些调用都会合并为一个带有最后一个调用参数的调用。例如,以下调用:
setProgress(1); setProgress(2); setProgress(3);
可能导致单个PropertyChangeListener通知,值为3。- 参数:
-
progress- 要设置的进度值 - 抛出:
-
IllegalArgumentException- 如果值不在0到100之间
-
getProgress
public final int getProgress()返回progress绑定属性。- 返回:
- 进度绑定属性。
-
execute
public final void execute()将此SwingWorker安排在工作线程上执行。有许多可用的工作线程。如果所有工作线程都忙于处理其他SwingWorker,则将此SwingWorker放入等待队列中。注意:
SwingWorker仅设计为执行一次。多次执行SwingWorker不会导致调用doInBackground方法两次。 -
cancel
public final boolean cancel(boolean mayInterruptIfRunning) 尝试取消此任务的执行。如果任务已经完成或取消,或者由于其他原因无法取消,则此方法不起作用。否则,如果在调用cancel时任务尚未启动,则此任务不应运行。如果任务已经启动,则mayInterruptIfRunning参数确定是否应中断执行此任务的线程(如果实现已知)以尝试停止任务。此方法的返回值并不一定表示任务现在已取消;请使用
Future.isCancelled()。 -
isCancelled
public final boolean isCancelled()如果此任务在正常完成之前被取消,则返回true。- 指定者:
-
isCancelled在接口Future<T>中 - 返回:
-
如果此任务在完成之前被取消,则返回
true
-
isDone
public final boolean isDone()如果此任务已完成,则返回true。完成可能是由于正常终止、异常或取消 - 在所有这些情况下,此方法将返回true。 -
get
必要时等待计算完成,然后检索其结果。注意:在事件分派线程上调用
get会阻塞所有事件,包括重绘事件,直到此SwingWorker完成。当您希望
SwingWorker在事件分派线程上阻塞时,我们建议您使用模态对话框。例如:
class SwingWorkerCompletionWaiter implements PropertyChangeListener { private JDialog dialog; public SwingWorkerCompletionWaiter(JDialog dialog) { this.dialog = dialog; } public void propertyChange(PropertyChangeEvent event) { if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) { dialog.setVisible(false); dialog.dispose(); } } } JDialog dialog = new JDialog(owner, true); swingWorker.addPropertyChangeListener( new SwingWorkerCompletionWaiter(dialog)); swingWorker.execute(); //对话框将一直可见,直到SwingWorker完成 dialog.setVisible(true);- 指定者:
-
get在接口Future<T>中 - 返回:
- 计算结果
- 抛出:
-
CancellationException- 如果计算被取消 -
InterruptedException- 如果当前线程在等待时被中断 -
ExecutionException- 如果计算引发异常
-
get
public final T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException - 指定者:
-
get在接口Future<T>中 - 参数:
-
timeout- 最长等待时间 -
unit- 超时参数的时间单位 - 返回值:
- 计算结果
- 抛出:
-
CancellationException- 如果计算被取消 -
InterruptedException- 如果当前线程在等待时被中断 -
ExecutionException- 如果计算抛出异常 -
TimeoutException- 如果等待超时
-
addPropertyChangeListener
向监听器列表中添加一个PropertyChangeListener。该监听器将被注册为所有属性的监听器。同一个监听器对象可以被添加多次,并且每次添加都会被调用。如果listener为null,则不会抛出异常,也不会执行任何操作。注意:这只是一个方便的包装器。所有工作都委托给
PropertyChangeSupport的getPropertyChangeSupport()方法。- 参数:
-
listener- 要添加的PropertyChangeListener
-
removePropertyChangeListener
从监听器列表中移除一个PropertyChangeListener。这将移除为所有属性注册的PropertyChangeListener。如果同一个事件源多次添加了listener,则在移除后将少通知一次。如果listener为null,或者从未添加过,则不会抛出异常,也不会执行任何操作。注意:这只是一个方便的包装器。所有工作都委托给
PropertyChangeSupport的getPropertyChangeSupport()方法。- 参数:
-
listener- 要移除的PropertyChangeListener
-
firePropertyChange
向所有注册的监听器报告一个绑定属性更新。如果old和new相等且非空,则不会触发事件。这个
SwingWorker将是任何生成事件的源。在事件分发线程之外调用时,
PropertyChangeListeners将在事件分发线程上异步通知。注意:这只是一个方便的包装器。所有工作都委托给
PropertyChangeSupport的getPropertyChangeSupport()方法。- 参数:
-
propertyName- 已更改的属性的程序名称 -
oldValue- 属性的旧值 -
newValue- 属性的新值
-
getPropertyChangeSupport
返回此SwingWorker的PropertyChangeSupport。当需要灵活访问绑定属性支持时使用此方法。这个
SwingWorker将是任何生成事件的源。注意:返回的
PropertyChangeSupport会在调用firePropertyChange或fireIndexedPropertyChange时,如果在事件分发线程之外调用,则会在事件分发线程上异步通知任何PropertyChangeListener。- 返回值:
-
此
SwingWorker的PropertyChangeSupport
-
getState
返回SwingWorker状态绑定属性。- 返回值:
- 当前状态
-