モジュール java.desktop
パッケージ javax.swing

クラスSwingWorker<T,V>

java.lang.Object
javax.swing.SwingWorker<T,V>
型パラメータ:
T - このSwingWorker'sdoInBackgroundメソッドおよびgetメソッドによって返される結果の型
V - このSwingWorker'spublishメソッドおよびprocessメソッドを使って中間結果を計算するために使用する型
すべての実装されたインタフェース:
Runnable, Future<T>, RunnableFuture<T>

public abstract class SwingWorker<T,V> extends Object implements RunnableFuture<T>
GUIとやりとりする時間のかかるタスクを、バックグラウンド・スレッドで実行するためのabstractクラスです。 複数のバックグラウンド・スレッドを使用してこうしたタスクを実行できます。 ただし、特定のSwingWorkerのスレッドを選択する厳密な方法は指定されていないため、それに依存してはいけません。

Swingを使用してマルチスレッド・アプリケーションを記述する場合は、次の2つの制約に注意してください(詳細は「Concurrency in Swing」を参照)。

  • イベント・ディスパッチ・スレッドでは時間のかかるタスクを実行しないようにしてください。 アプリケーションが応答しなくなります。
  • Swingコンポーネントには、イベント・ディスパッチ・スレッド上でのみアクセスするようにしてください。

これらの制約があるため、時間のかかるGUIアプリケーションには、1)時間のかかるタスクを実行するスレッドと、2) GUI関連のすべての作業を実行するイベント・ディスパッチ・スレッド (EDT)の少なくとも2つのスレッドが必要になります。 このように複数のスレッドを使用する場合はスレッド間通信を行う必要がありますが、この機能は簡単に実装できない場合があります。

SwingWorkerは、バックグラウンド・スレッドで実行時間の長いタスクを実行する必要があり、その実行中または実行完了後にUIを更新する必要がある場合を想定して設計されています。 SwingWorkerのサブクラスは、バックグラウンドで計算を行うため、doInBackground()メソッドを実装する必要があります。

ワークフロー

SwingWorkerのライフ・サイクル内には、次の3つのスレッドが存在します。

  • 現在のスレッド: execute()メソッドはこのスレッド上で呼び出されます。 このメソッドは、ワーカー・スレッドでのSwingWorkerの実行スケジュールを立て、その情報をただちに返します。 getメソッドを使ってSwingWorkerの完了を待機することもできます。

  • ワーカー・スレッド: doInBackground()メソッドはこのスレッド上で呼び出されます。 ここで、すべてのバックグラウンド作業が発生します。 PropertyChangeListenersにバウンド・プロパティの変更を通知するには、firePropertyChangeメソッドとgetPropertyChangeSupport()メソッドを使用します。 デフォルトでは、stateprogressの2つのバウンド・プロパティを使用できます。

  • イベント・ディスパッチ・スレッド: Swing関連のすべての作業は、このスレッド上で発生します。 SwingWorkerprocessメソッドと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
 

SwingWorkerRunnableを実装するので、SwingWorkerExecutorに送信して実行できます。

導入されたバージョン:
1.6