- java.lang.Object
-
- javax.swing.SwingWorker<T,V>
-
- 参数类型
-
T
- 该SwingWorker's
doInBackground
和get
方法返回的结果类型 -
V
- 用于执行中间结果的类型SwingWorker's
publish
和process
方法
- All Implemented Interfaces:
-
Runnable
,Future<T>
,RunnableFuture<T>
public abstract class SwingWorker<T,V> extends Object implements RunnableFuture<T>
在后台线程中执行冗长的GUI交互任务的抽象类。 可以使用几个后台线程来执行这些任务。 然而,为任何特定的SwingWorker
选择一个线程的确切策略是未指定的,不应该依赖。当使用Swing编写多线程应用程序时,请注意以下两个限制:(有关详细信息,请参阅Concurrency in Swing ):
- 事件调度线程不应该运行耗时的任务。 否则应用程序将无响应。
- 只能在事件分派线程上访问Swing组件。
这些限制意味着具有时间密集型计算的GUI应用程序至少需要两个线程:1)执行冗长任务的线程; 2)所有GUI相关活动的事件调度线程 (EDT)。 这涉及到可能难以实现的跨线程通信。
SwingWorker
适用于需要在后台线程中运行长时间运行的任务并在完成或处理时向UI提供更新的情况。SwingWorker
子类必须实现doInBackground()
方法来执行后台计算。工作流程
一个
SwingWorker
的生命周期涉及三个线程:当前线程:在这个线程上调用了
execute()
方法。 它在工作线程上执行SwingWorker
,并立即返回。 可以等待SwingWorker
完成使用get
方法。工作线程:在这个线程上调用了
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
执行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) { //initialize }
@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()); //prints all prime numbers we have got因为
SwingWorker
实现Runnable
,一个SwingWorker
可以提交给一个Executor
执行。- 从以下版本开始:
- 1.6
-
-
Nested Class Summary
Nested Classes Modifier and Type Class 描述 static class
SwingWorker.StateValue
state
绑定属性的值。
-
构造方法摘要
构造方法 Constructor 描述 SwingWorker()
构造这个SwingWorker
。
-
方法摘要
所有方法 接口方法 抽象方法 具体的方法 Modifier and Type 方法 描述 void
addPropertyChangeListener(PropertyChangeListener listener)
添加一个PropertyChangeListener
到监听器列表。boolean
cancel(boolean mayInterruptIfRunning)
尝试取消执行此任务。protected abstract T
doInBackground()
计算一个结果,如果不能这样做,就会抛出一个异常。protected void
done()
doInBackground
方法完成后,在 事件发送doInBackground
执行。void
execute()
计划这个SwingWorker
在 工作线程上执行。void
firePropertyChange(String propertyName, Object oldValue, Object newValue)
向任何已注册的监听器报告绑定属性更新。T
get()
等待计算完成,然后检索其结果。T
get(long timeout, TimeUnit unit)
如果需要等待最多在给定的时间计算完成,然后检索其结果(如果可用)。int
getProgress()
返回progress
绑定属性。PropertyChangeSupport
getPropertyChangeSupport()
返回这个PropertyChangeSupport
的SwingWorker
。SwingWorker.StateValue
getState()
返回SwingWorker
状态绑定属性。boolean
isCancelled()
如果此任务在正常完成之前被取消,则返回true
。boolean
isDone()
如果此任务完成,则返回true
。protected void
process(List<V> chunks)
在 事件调度线程上异步接收来自publish
方法的数据块。protected void
publish(V... chunks)
发送数据块到process(java.util.List<V>)
方法。void
removePropertyChangeListener(PropertyChangeListener listener)
从侦听器列表中删除PropertyChangeListener
。void
run()
将此Future
设置为计算结果,除非已被取消。protected void
setProgress(int progress)
设置progress
绑定属性。
-
-
-
方法详细信息
-
doInBackground
protected abstract T doInBackground() throws 异常
计算一个结果,如果不能这样做,就会抛出一个异常。请注意,此方法只执行一次。
注意:该方法在后台线程中执行。
- 结果
- 计算结果
- 异常
-
异常
- 如果无法计算结果
-
run
public final void run()
将此Future
设置为计算结果,除非已被取消。- Specified by:
-
run
在接口Runnable
- Specified by:
-
run
在接口RunnableFuture<T>
- 另请参见:
-
Thread.run()
-
publish
@SafeVarargs protected final void publish(V... chunks)
发送数据块到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
方法中process
。class TableSwingWorker extends SwingWorker<DefaultTableModel, Object[]> { private final DefaultTableModel tableModel; public TableSwingWorker(DefaultTableModel tableModel) { this.tableModel = tableModel; }
@Override
protected DefaultTableModel doInBackground() throws Exception { for (Object[] row = loadData(); ! isCancelled() && row != null; row = loadData()) { publish((Object[]) row); } return tableModel; }@Override
protected void process(List<Object[]> chunks) { for (Object[] row : chunks) { tableModel.addRow(row); } } }- 参数
-
chunks
- 要处理的中间结果 - 另请参见:
-
process(java.util.List<V>)
-
process
protected void process(List<V> chunks)
在事件调度线程上异步接收来自publish
方法的数据块。详情请参考
publish(V...)
方法。- 参数
-
chunks
- 要处理的中间结果 - 另请参见:
-
publish(V...)
-
done
protected void done()
完成doInBackground
方法后,在事件发送doInBackground
执行。 默认实现什么都不做。 子类可以覆盖此方法以在事件分派线程上执行完成操作。 请注意,您可以在该方法的实现中查询状态,以确定此任务的结果或此任务是否已被取消。- 另请参见:
-
doInBackground()
,isCancelled()
,get()
-
setProgress
protected final void setProgress(int progress)
设置progress
绑定属性。 该值应该在0到100之间。因为
PropertyChangeListener
在事件调度线程上被异步通知,因此在调用任何PropertyChangeListeners
之前,可能会发生多项到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
用于在工作线程上执行。 有多个工作线程可用。 在所有工作线程正忙于处理其他SwingWorkers
情况下,SwingWorker
被放置在等待队列中。注意:
SwingWorker
仅被设计为执行一次。SwingWorker
执行SwingWorker
不会导致二次调用doInBackground
方法。
-
cancel
public final boolean cancel(boolean mayInterruptIfRunning)
尝试取消执行此任务。 如果任务已经完成,已经被取消或由于某种其他原因而无法取消,则此尝试将失败。 如果成功,并且当cancel
时此任务尚未启动,则此任务不应运行。 如果任务已经开始,那么mayInterruptIfRunning
参数确定执行此任务的线程是否应该中断,以试图停止任务。此方法返回后,后续调用
Future.isDone()
将始终返回true
。 对后续调用Future.isCancelled()
总是返回true
如果此方法返回true
。
-
isCancelled
public final boolean isCancelled()
如果此任务在正常完成之前被取消,则返回true
。- Specified by:
-
isCancelled
在接口Future<T>
- 结果
-
true
如果此任务在完成之前被取消
-
isDone
public final boolean isDone()
如果此任务完成,则返回true
。 完成可能是由于正常终止,异常或取消 - 在所有这些情况下,此方法将返回true
。
-
get
public final T get() throws InterruptedException, ExecutionException
等待计算完成,然后检索其结果。注意:在事件分派线程上调用
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(); //the dialog will be visible until the SwingWorker is done dialog.setVisible(true);
- Specified by:
-
get
在接口Future<T>
- 结果
- 计算结果
- 异常
-
InterruptedException
- 如果当前线程在等待时中断 -
ExecutionException
- 如果计算抛出异常
-
get
public final T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
如果需要等待最多在给定的时间计算完成,然后检索其结果(如果可用)。详情请参阅
get()
。- Specified by:
-
get
在接口Future<T>
- 参数
-
timeout
- 等待的最长时间 -
unit
- 超时参数的时间单位 - 结果
- 计算结果
- 异常
-
InterruptedException
- 如果当前线程在等待时中断 -
ExecutionException
- 如果计算抛出异常 -
TimeoutException
- 如果等待超时
-
addPropertyChangeListener
public final void addPropertyChangeListener(PropertyChangeListener listener)
添加一个PropertyChangeListener
到监听器列表。 所有属性都注册了监听器。 同一个侦听器对象可以被多次添加,并且将被调用多次,因为它被添加。 如果listener
为null
,则不会抛出异常并且不采取任何操作。注意:这只是一个方便的包装。 所有工作
PropertyChangeSupport
getPropertyChangeSupport()
委派至PropertyChangeSupport 。- 参数
-
listener
- 要添加的PropertyChangeListener
-
removePropertyChangeListener
public final void removePropertyChangeListener(PropertyChangeListener listener)
从侦听器列表中删除PropertyChangeListener
。 这将删除所有属性注册的PropertyChangeListener
。 如果listener
添加到同一个事件源,则被删除后将被通知一次。 如果listener
是null
,或者从未添加过,则不会抛出异常并且不采取任何操作。注意:这只是一个方便的包装。 所有的工作都委托给
PropertyChangeSupport
从getPropertyChangeSupport()
。- 参数
-
listener
- 要删除的PropertyChangeListener
-
firePropertyChange
public final void firePropertyChange(String propertyName, Object oldValue, Object newValue)
向任何已注册的监听器报告绑定属性更新。 如果old
和new
相等且非空,则old
触发任何事件。这个
SwingWorker
将是任何生成的事件的源。当调用事件调度线程
PropertyChangeListeners
被异步通知事件分派线程时 。注意:这只是一个方便的包装。 所有的工作都委托给
PropertyChangeSupport
从getPropertyChangeSupport()
。- 参数
-
propertyName
- 已更改的属性的编程名称 -
oldValue
- 该物业的旧值 -
newValue
- 该物业的新值
-
getPropertyChangeSupport
public final PropertyChangeSupport getPropertyChangeSupport()
返回PropertyChangeSupport
为这个SwingWorker
。 当需要灵活访问绑定属性支持时,使用此方法。这个
SwingWorker
将是任何生成的事件的源。注:返回
PropertyChangeSupport
通知任何PropertyChangeListener
小号异步对事件的事件调度线程firePropertyChange
或者fireIndexedPropertyChange
被叫停事件指派线程 。- 结果
-
PropertyChangeSupport
为这SwingWorker
-
getState
public final SwingWorker.StateValue getState()
返回SwingWorker
状态绑定属性。- 结果
- 当前状态
-
-