モジュール java.desktop
パッケージ 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
    • ネストされたクラスのサマリー

      ネストされたクラス 
      修飾子と型 クラス 説明
      static class  SwingWorker.StateValue
      stateバウンド・プロパティの値です。
    • コンストラクタのサマリー

      コンストラクタ 
      コンストラクタ 説明
      SwingWorker()
      このSwingWorkerを構築します。
    • コンストラクタの詳細

      • SwingWorker

        public SwingWorker()
        このSwingWorkerを構築します。
    • メソッドの詳細

      • doInBackground

        protected abstract T doInBackground()
                                     throws Exception
        結果を計算するか、計算できない場合は例外をスローします。

        このメソッドは1回だけ実行されます。

        注: このメソッドは、バックグラウンド・スレッドで実行されます。

        戻り値:
        計算結果
        例外:
        Exception - 結果を計算できなかった場合
      • run

        public final void run()
        取り消されていなければ、このFutureに計算結果を設定します。
        定義:
        run、インタフェース: Runnable
        定義:
        run、インタフェース: RunnableFuture<T>
        関連項目:
        Thread.run()
      • publish

        @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>)
      • process

        protected void process​(List<V> chunks)
        イベント・ディスパッチ・スレッドで、publishメソッドから非同期でデータ・チャンクを受信します。

        詳細については、publish(V...)メソッドを参照してください。

        パラメータ:
        chunks - 処理対象となる中間結果
        関連項目:
        publish(V...)
      • done

        protected void done()
        doInBackgroundメソッドの実行完了後、イベント・ディスパッチ・スレッドで実行されます。 デフォルト実装は何も実行しません。 サブクラスは、このメソッドをオーバーライドして、イベント・ディスパッチ・スレッド上で完了処理を実行することがあります。 このメソッドの実装内部でステータスを照会して、このタスクの結果や、このタスクが取り消されていないかどうかを確認できます。
        関連項目:
        doInBackground(), Future.isCancelled(), get()
      • setProgress

        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以外の値を指定した場合
      • getProgress

        public final int getProgress()
        progressバウンド・プロパティを返します。
        戻り値:
        progressバウンド・プロパティ。
      • execute

        public final void execute()
        ワーカー・スレッドでのSwingWorkerの実行スケジュールを作成します。 多数のワーカー・スレッドを使用できます。 すべてのワーカー・スレッドがほかのSwingWorkersの処理でビジー状態になっている場合、このSwingWorkerは待機キューに入ります。

        注: SwingWorkerは1回だけ実行されるように設計されています。 SwingWorkerを複数回実行しても、doInBackgroundメソッドは1回しか呼び出されません。

      • 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);
         
        定義:
        get、インタフェース: Future<T>
        戻り値:
        計算結果
        例外:
        InterruptedException - 待機中に現在のスレッドで割込みが発生した場合
        ExecutionException - 計算で例外がスローされた場合
      • get

        public final T get​(long timeout,
                           TimeUnit unit)
                    throws InterruptedException,
                           ExecutionException,
                           TimeoutException
        必要に応じて、最大で指定された時間、計算が完了するまで待機し、その後、計算結果が利用可能な場合は結果を取得します。

        詳細については、get()を参照してください。

        定義:
        get、インタフェース: Future<T>
        パラメータ:
        timeout - 待機する最長時間
        unit - timeout引数の時間単位
        戻り値:
        計算結果
        例外:
        InterruptedException - 待機中に現在のスレッドで割込みが発生した場合
        ExecutionException - 計算で例外がスローされた場合
        TimeoutException - 待機がタイム・アウトになった場合
      • addPropertyChangeListener

        public final void addPropertyChangeListener​(PropertyChangeListener listener)
        リスナー・リストにPropertyChangeListenerを追加します。 リスナーは、すべてのプロパティに対して登録されます。 同じリスナー・オブジェクトを複数回追加でき、追加した回数だけリスナー・オブジェクトが呼び出されます。 listenernullの場合、例外はスローされず、何も処理は行われません。

        注: これは簡易ラッパーです。 すべての処理は、getPropertyChangeSupport()からPropertyChangeSupportに委譲されます。

        パラメータ:
        listener - 追加されるPropertyChangeListener
      • removePropertyChangeListener

        public final void removePropertyChangeListener​(PropertyChangeListener listener)
        PropertyChangeListenerをリスナー・リストから削除します。 すべてのプロパティに登録されたPropertyChangeListenerを削除します。 同じイベント・ソースにlistenerが2回以上追加された場合は、削除されたあとに1回少ない通知が行われます。 listenernullの場合、または追加されなかった場合、例外はスローされず、何も処理は行われません。

        注: これは簡易ラッパーです。 すべての処理は、getPropertyChangeSupport()からPropertyChangeSupportに委譲されます。

        パラメータ:
        listener - 削除するPropertyChangeListener
      • firePropertyChange

        public final void firePropertyChange​(String propertyName,
                                             Object oldValue,
                                             Object newValue)
        すべての登録済みリスナーにバウンド・プロパティが更新されたことを報告します。 old値とnew値が等しく、nullでない場合、イベントはトリガーされません。

        このSwingWorkerは、生成されるすべてのイベントのソースになります。

        イベント・ディスパッチ・スレッドを取り消した場合、PropertyChangeListenersイベント・ディスパッチ上で非同期で通知を受信します。

        注: これは簡易ラッパーです。 すべての処理は、getPropertyChangeSupport()からPropertyChangeSupportに委譲されます。

        パラメータ:
        propertyName - 変更されたプロパティのプログラム名
        oldValue - プロパティの古い値
        newValue - プロパティの新しい値
      • getPropertyChangeSupport

        public final PropertyChangeSupport getPropertyChangeSupport()
        このSwingWorkerPropertyChangeSupportを返します。 このメソッドは、バウンド・プロパティに頻繁にアクセスする必要がある場合に使用します。

        このSwingWorkerは、生成されるすべてのイベントのソースになります。

        注: firePropertyChangeまたはfireIndexedPropertyChangeイベント・ディスパッチ・スレッドを取り消した場合、返されるPropertyChangeSupportは、イベント・ディスパッチ・スレッド上のすべてのPropertyChangeListenerに非同期で通知を送信します。

        戻り値:
        このSwingWorkerPropertyChangeSupport
      • getState

        public final SwingWorker.StateValue getState()
        SwingWorker状態バウンド・プロパティを返します。
        戻り値:
        現在の状態