T
- 此
SwingWorker's
doInBackground
和
get
方法返回的结果类型
V
- 用于执行中间结果的类型
SwingWorker's
publish
和
process
方法
public abstract class SwingWorker<T,V> extends Object implements RunnableFuture<T>
SwingWorker
选择一个线程的确切策略是未指定的,不应该依赖。
当使用Swing编写多线程应用程序时,请注意以下两个限制:(有关详细信息,请参阅Concurrency in Swing ):
这些限制意味着具有时间密集型计算的GUI应用程序至少需要两个线程:1)执行冗长任务的线程; 2)所有GUI相关活动的事件调度线程 (EDT)。 这涉及到可能难以实现的跨线程通信。
SwingWorker
适用于需要在后台线程中运行长时间运行的任务并在完成或处理时向UI提供更新的情况。 SwingWorker的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
不会导致调用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
执行。
Modifier and Type | Class and Description |
---|---|
static class |
SwingWorker.StateValue
值为
state 绑定属性。
|
Constructor and Description |
---|
SwingWorker()
构造这个
SwingWorker 。
|
Modifier and Type | Method and Description |
---|---|
void |
addPropertyChangeListener(PropertyChangeListener listener)
添加一个
PropertyChangeListener 到侦听器列表。
|
boolean |
cancel(boolean mayInterruptIfRunning)
尝试取消执行此任务。
|
protected abstract T |
doInBackground()
计算一个结果,如果不能这样做,就会抛出一个异常。
|
protected void |
done()
在
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 从
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 绑定属性。
|
protected abstract T doInBackground() throws 异常
请注意,此方法只执行一次。
注意:该方法在后台线程中执行。
异常
- 如果无法计算结果
public final void run()
Future
设置为计算结果,除非已被取消。
run
在接口
Runnable
run
在接口
RunnableFuture<T>
Thread.run()
@SafeVarargs protected final void publish(V... chunks)
process(java.util.List<V>)
方法。
此方法是从里面使用doInBackground
方法在里面的事件指派线程提供用于处理中间结果process
方法。
因为process
方法是异步调用的事件指派线程多次调用到publish
方法之前,可能会出现process
执行方法。 为了表现目的,所有这些调用都合并成一个带有连接参数的调用。
例如:
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>)
protected void process(List<V> chunks)
publish
从publish
方法接收数据块。
有关详细信息,请参阅publish(V...)
方法。
chunks
- 要处理的中间结果
publish(V...)
protected void done()
doInBackground
方法完成后在事件调度线程上执行。
默认实现什么都不做。
子类可以覆盖此方法以在事件分派线程上执行完成操作。
请注意,您可以在该方法的实现中查询状态,以确定此任务的结果或此任务是否已被取消。
doInBackground()
,
isCancelled()
,
get()
protected final void setProgress(int progress)
progress
绑定属性。
该值应该在0到100之间。
因为PropertyChangeListener
在事件调度线程上PropertyChangeListener
通知,在调用任何PropertyChangeListeners
之前,可能会发生对setProgress
方法的PropertyChangeListeners
调用。 为了执行目的,所有这些调用都合并到一个调用中,最后一个调用参数。
例如,以下调用:
setProgress(1);
setProgress(2);
setProgress(3);
可能会导致一个单独的PropertyChangeListener
通知,值为3
。
progress
- 要设置的进度值
IllegalArgumentException
- 值不是从0到100
public final int getProgress()
progress
绑定属性。
public final void execute()
SwingWorker
以在工作线程上执行。
有多个工作线程可用。
在所有工作线程正忙于处理其他SwingWorkers
这SwingWorker
被放置在等待队列中。
注意: SwingWorker
仅被设计为执行一次。 多次执行SwingWorker
不会导致调用doInBackground
方法两次。
public final boolean cancel(boolean mayInterruptIfRunning)
cancel
被调用时,这个任务应该运行。
如果任务已经开始,那么mayInterruptIfRunning
参数确定是否执行此任务的线程应该以试图停止任务被中断。
此方法返回后,后续调用Future.isDone()
将始终返回true
。 随后电话Future.isCancelled()
总是返回true
如果此方法返回true
。
public final boolean isCancelled()
true
。
isCancelled
在接口
Future<T>
true
如果此任务在完成之前被取消
public final boolean isDone()
true
如果任务已完成。
完成可能是由于正常终止,异常或取消 - 在所有这些情况下,此方法将返回true
。
public final T get() throws InterruptedException, ExecutionException
注意:在事件调度线程上调用get
阻止所有事件(包括重绘)被处理直到此SwingWorker
完成。
当您想要SwingWorker
阻止事件调度线程时,我们建议您使用模态对话框 。
例如:
class SwingWorkerCompletionWaiter extends 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);
get
在接口
Future<T>
InterruptedException
- 如果当前线程在等待时中断
ExecutionException
- 如果计算抛出异常
public final T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
详情请参考get()
。
get
在接口
Future<T>
timeout
- 等待的最长时间
unit
- 超时参数的时间单位
InterruptedException
- 如果当前线程在等待时中断
ExecutionException
- 如果计算引发异常
TimeoutException
- 如果等待超时
public final void addPropertyChangeListener(PropertyChangeListener listener)
PropertyChangeListener
到监听器列表。
所有属性都注册了监听器。
同一个侦听器对象可以被多次添加,并且将被调用多次,因为它被添加。
如果listener
是null
,那么抛出异常并且不采取任何操作。
注意:这只是一个方便的包装。 所有工作由getPropertyChangeSupport()
PropertyChangeSupport
至PropertyChangeSupport 。
listener
- 要加入的
PropertyChangeListener
public final void removePropertyChangeListener(PropertyChangeListener listener)
PropertyChangeListener
。
这消除了一个PropertyChangeListener
已注册的所有属性。
如果listener
添加到同一个事件源, listener
删除后将被通知一次。
如果listener
是null
,或者从未添加过,则不会抛出任何异常,也不会采取任何操作。
注意:这只是一个方便的包装。 所有工作由getPropertyChangeSupport()
PropertyChangeSupport
给PropertyChangeSupport 。
listener
- 要删除的
PropertyChangeListener
public final void firePropertyChange(String propertyName, Object oldValue, Object newValue)
old
和new
相等且非空,则old
触发任何事件。
这SwingWorker
将是任何生成的事件的源。
如果取消了事件指派线程 PropertyChangeListeners
是在事件指派线程上异步地通知。
注意:这只是一个方便的包装。 所有工作均由PropertyChangeSupport
至PropertyChangeSupport 。
propertyName
- 已更改的属性的编程名称
oldValue
- 该属性的旧值
newValue
- 该物业的新值
public final PropertyChangeSupport getPropertyChangeSupport()
PropertyChangeSupport
为这SwingWorker
。
当需要灵活访问绑定属性支持时,使用此方法。
此SwingWorker
将是任何生成的事件的源。
注:返回PropertyChangeSupport
通知任何PropertyChangeListener
小号异步对事件的事件调度线程 firePropertyChange
或fireIndexedPropertyChange
被叫停事件指派线程 。
PropertyChangeSupport
为这
SwingWorker
public final SwingWorker.StateValue getState()
SwingWorker
状态绑定属性。