T - このSwingWorker'sのdoInBackgroundメソッドおよびgetメソッドによって返される結果の型V - このSwingWorker'sのpublishメソッドおよびprocessメソッドを使って中間結果を計算するために使用する型public abstract class SwingWorker<T,V> extends Object implements RunnableFuture<T>
SwingWorkerのスレッドを選択する厳密な方法は指定されていないため、それに依存してはいけません。
Swingを使用してマルチスレッド・アプリケーションを記述する場合は、次の2つの制約に注意してください(詳細は「Concurrency in Swing」を参照)。
これらの制約があるため、時間のかかるGUIアプリケーションには、1)時間のかかるタスクを実行するスレッドと、2) GUI関連のすべての作業を実行するイベント・ディスパッチ・スレッド (EDT)の少なくとも2つのスレッドが必要になります。このように複数のスレッドを使用する場合はスレッド間通信を行う必要がありますが、この機能は簡単に実装できない場合があります。
SwingWorkerは、バックグラウンド・スレッドで実行時間の長いタスクを実行する必要があり、その実行中または実行完了後にUIを更新する必要がある場合を想定して設計されています。SwingWorkerのサブクラスは、バックグラウンドで計算を行うため、doInBackground()メソッドを実装する必要があります。
ワークフロー
SwingWorkerのライフ・サイクル内には、次の3つのスレッドが存在します。
現在のスレッド: execute()メソッドはこのスレッド上で呼び出されます。このメソッドは、ワーカースレッドでのSwingWorkerの実行スケジュールを立て、その情報をただちに返します。getメソッドを使ってSwingWorkerの完了を待機することもできます。
ワーカースレッド: doInBackground()メソッドはこのスレッド上で呼び出されます。ここで、すべてのバックグラウンド作業が発生します。PropertyChangeListenersにバウンド・プロパティの変更を通知するには、firePropertyChangeメソッドとgetPropertyChangeSupport()メソッドを使用します。デフォルトでは、stateとprogressの2つのバウンド・プロパティを使用できます。
イベント・ディスパッチ・スレッド: Swing関連のすべての作業は、このスレッド上で発生します。SwingWorkerはprocessメソッドとdone()メソッドを呼び出し、このスレッド上のすべてのPropertyChangeListenersに通知します。
現在のスレッドがイベント・ディスパッチ・スレッドである場合もあります。
ワーカースレッド上でdoInBackgroundメソッドが呼び出される前に、SwingWorkerはすべてのPropertyChangeListenersに、stateプロパティの値がStateValue.STARTEDに変更されたことを通知します。doInBackgroundメソッドの実行が完了すると、doneメソッドが実行されます。続いて、SwingWorkerはすべてのPropertyChangeListenersに、stateプロパティの値がStateValue.DONEに変更されたことを通知します。
SwingWorkerは1回だけ実行されるように設計されています。SwingWorkerを複数回実行しても、doInBackgroundメソッドは1回しか呼び出されません。
使用例
次に、もっとも単純な使用例を示します。一部の処理はバックグラウンドで実行されます。実行が完了したら、Swingコンポーネントを更新します。
ここでは、「Meaning of Life」を検索し、結果を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に送信して実行できます。
| 修飾子と型 | クラスと説明 |
|---|---|
static class |
SwingWorker.StateValue
stateバウンド・プロパティの値です。 |
| コンストラクタと説明 |
|---|
SwingWorker()
この
SwingWorkerを構築します。 |
| 修飾子と型 | メソッドと説明 |
|---|---|
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()
この
SwingWorkerのPropertyChangeSupportを返します。 |
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バウンド・プロパティを設定します。 |
protected abstract T doInBackground() throws Exception
このメソッドは1回だけ実行されます。
注: このメソッドは、バックグラウンド・スレッドで実行されます。
Exception - 結果を計算できなかった場合public final void run()
Futureに計算結果を設定します。run、インタフェース: Runnablerun、インタフェース: RunnableFuture<T>Thread.run()@SafeVarargs protected final void publish(V... chunks)
process(java.util.List<V>)メソッドにデータ・チャンクを送信します。このメソッドはdoInBackgroundメソッド内部で使用され、イベント・ディスパッチ・スレッド上での処理のためprocessメソッド内部で中間結果を配信します。
processメソッドはイベント・ディスパッチ・スレッド上で非同期で呼び出されるので、processメソッドが実行される前に、publishメソッドが複数回呼び出されることがあります。パフォーマンスの向上のため、これらのすべての呼出しは1回の呼出しにまとめられます。各呼出しの引数は連結されます。
例を示します。
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;
}
@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(V...)メソッドを参照してください。
chunks - 処理対象となる中間結果publish(V...)protected void done()
doInBackgroundメソッドの実行完了後、イベント・ディスパッチ・スレッドで実行されます。デフォルト実装は何も実行しません。サブクラスは、このメソッドをオーバーライドして、イベント・ディスパッチ・スレッド上で完了処理を実行することがあります。このメソッドの実装内部でステータスを照会して、このタスクの結果や、このタスクが取り消されていないかどうかを確認できます。doInBackground(), isCancelled(), get()protected final void setProgress(int progress)
progressバウンド・プロパティを設定します。0から100の値を指定してください。
PropertyChangeListenerメソッドはイベント・ディスパッチ・スレッド上で非同期で通知を受け取るので、PropertyChangeListenersが呼び出される前に、setProgressメソッドが複数回呼び出されることがあります。パフォーマンスの向上のため、これらのすべての呼出しは1回の呼出しにまとめられます。この場合、最後の呼出しの引数のみが有効になります。
たとえば、次の呼出しがあるとします。
setProgress(1); setProgress(2); setProgress(3);これは、値
3を持つ1回のPropertyChangeListener通知にまとめられます。progress - 設定する進捗値IllegalArgumentException - 0から100以外の値を指定した場合public final int getProgress()
progressバウンド・プロパティを返します。public final void execute()
SwingWorkerの実行スケジュールを作成します。多数のワーカースレッドを使用できます。すべてのワーカースレッドがほかのSwingWorkersの処理でビジー状態になっている場合、このSwingWorkerは待機キューに入ります。
注: SwingWorkerは1回だけ実行されるように設計されています。SwingWorkerを複数回実行しても、doInBackgroundメソッドは1回しか呼び出されません。
public final boolean cancel(boolean mayInterruptIfRunning)
cancelの呼出し時にこのタスクが起動しなかった場合、このタスクが実行されることはありません。タスクが起動済みの場合は、このタスクの停止を試みる際、このタスクを実行しているスレッドに割り込む必要があるかどうかは、mayInterruptIfRunningパラメータで判断します。
このメソッドが復帰すると、その後のFuture.isDone()の呼出しは常にtrueを返します。このメソッドがtrueを返した場合、後続のFuture.isCancelled()の呼出しは常にtrueを返します。
public final boolean isCancelled()
trueを返します。isCancelled、インタフェース: Future<T>truepublic 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 - timeout引数の時間単位InterruptedException - 待機中に現在のスレッドで割込みが発生した場合ExecutionException - 計算で例外がスローされた場合TimeoutException - 待機がタイム・アウトになった場合public final void addPropertyChangeListener(PropertyChangeListener listener)
PropertyChangeListenerを追加します。リスナーは、すべてのプロパティに対して登録されます。同じリスナー・オブジェクトを複数回追加でき、追加した回数だけリスナー・オブジェクトが呼び出されます。listenerがnullの場合、例外はスローされず、何も処理は行われません。
注: これは簡易ラッパーです。すべての処理は、getPropertyChangeSupport()からPropertyChangeSupportに委譲されます。
listener - 追加されるPropertyChangeListenerpublic final void removePropertyChangeListener(PropertyChangeListener listener)
PropertyChangeListenerをリスナー・リストから削除します。すべてのプロパティに登録されたPropertyChangeListenerを削除します。同じイベント・ソースにlistenerが2回以上追加された場合は、削除されたあとに1回少ない通知が行われます。listenerがnullの場合、または追加されなかった場合、例外はスローされず、何も処理は行われません。
注: これは簡易ラッパーです。すべての処理は、getPropertyChangeSupport()からPropertyChangeSupportに委譲されます。
listener - 削除するPropertyChangeListenerpublic final void firePropertyChange(String propertyName, Object oldValue, Object newValue)
old値とnew値が等しく、nullでない場合、イベントはトリガーされません。
このSwingWorkerは、生成されるすべてのイベントのソースになります。
イベント・ディスパッチ・スレッドを取り消した場合、PropertyChangeListenersはイベント・ディスパッチ上で非同期で通知を受信します。
注: これは簡易ラッパーです。すべての処理は、getPropertyChangeSupport()からPropertyChangeSupportに委譲されます。
propertyName - 変更されたプロパティのプログラム名oldValue - プロパティの古い値newValue - プロパティの新しい値public final PropertyChangeSupport getPropertyChangeSupport()
SwingWorkerのPropertyChangeSupportを返します。このメソッドは、バウンド・プロパティに頻繁にアクセスする必要がある場合に使用します。
このSwingWorkerは、生成されるすべてのイベントのソースになります。
注: firePropertyChangeまたはfireIndexedPropertyChangeがイベント・ディスパッチ・スレッドを取り消した場合、返されるPropertyChangeSupportは、イベント・ディスパッチ・スレッド上のすべてのPropertyChangeListenerに非同期で通知を送信します。
SwingWorkerのPropertyChangeSupportpublic final SwingWorker.StateValue getState()
SwingWorker状態バウンド・プロパティを返します。 バグまたは機能を送信
詳細なAPIリファレンスおよび開発者ドキュメントについては、Java SEのドキュメントを参照してください。そのドキュメントには、概念的な概要、用語の定義、回避方法、有効なコード例などの、開発者を対象にしたより詳細な説明が含まれています。
Copyright© 1993, 2014, Oracle and/or its affiliates. All rights reserved.