Java
 Computer >> コンピューター >  >> プログラミング >> Java

JavaのSwingUtilitiesクラスとは?invokeAndWait()とinvokeLater()で実現するスレッドセーフなGUI操作


JavaのSwingでは、コンポーネントが画面に表示された後、それらを操作できるのは「イベントディスパッチスレッド(Event Handling Thread)」と呼ばれる単一のスレッドだけです。これはSwingの重要な設計原則であり、複数のスレッドから同時にGUIを操作すると不整合や予期しない動作が発生するため、すべての描画・更新処理をこのスレッドに集約することで安全性を確保しています。

開発者は、別途作成したコードブロックの参照をイベントディスパッチスレッドに渡すことができます。SwingUtilitiesクラスには、そのための2つの重要なstaticメソッド、invokeAndWait()invokeLater()が用意されており、これらを使うことでコードブロックへの参照をイベントキューに登録できます。

構文

public static void invokeAndWait(Runnable doRun) throws InterruptedException, InvocationTargetException
public static void invokeLater(Runnable doRun)

引数doRunは、Runnableインターフェースのインスタンスへの参照です。ここで注意したいのは、RunnableインターフェースがThreadのコンストラクタに渡されるわけではないという点です。この場面では、Runnableインターフェースは単にイベントスレッドのエントリポイント(処理の開始点)を識別するための手段として使われています。新しく起動されたスレッドがrun()メソッドを呼び出すのと同じように、イベントスレッドもキューに溜まっている他の保留中のイベントをすべて処理し終えた時点で、run()メソッドを呼び出します。

これらのメソッドに関連する例外は以下の通りです。

  • InterruptedException:対象のコードブロックが完了する前に、invokeAndWait()またはinvokeLater()を呼び出したスレッドが割り込みを受けた場合にスローされます。
  • InvocationTargetException:run()メソッド内のコードが、キャッチされない例外をスローした場合に発生します。

invokeAndWait()とinvokeLater()の違い

invokeAndWait()は、指定したコードブロックがイベントスレッド上で実行され完了するまで、呼び出し元のスレッドをブロックします。一方invokeLater()は、コードブロックをイベントキューに登録した直後にすぐ制御を返すため、呼び出し元は処理の完了を待たずに次の処理へ進めます。UIの初期化のように処理順序が重要な場面ではinvokeAndWait()が、単なる非同期のUI更新であればinvokeLater()が適しています。

サンプルコード

import javax.swing.*;
import java.lang.reflect.InvocationTargetException;

public class SwingUtilitiesTest {
    public static void main(String[] args) {
        final JButton button = new JButton("Not Changed");
        JPanel panel = new JPanel();
        panel.add(button);
        JFrame f = new JFrame("InvokeAndWaitMain");
        f.setContentPane(panel);
        f.setSize(300, 100);
        f.setVisible(true);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        System.out.println(Thread.currentThread().getName()+" is going into sleep for 3 seconds");
        try {
            Thread.sleep(3000);
        } catch(Exception e){ }
        // ラベル変更用のコードを準備
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"is going into sleep for 10 seconds");
                try {
                    Thread.sleep(10000);
                } catch(Exception e){ }
                button.setText("Button Text Changed by "+ Thread.currentThread().getName());
                System.out.println("Button changes ended");
            }
        };
        System.out.println("Component changes put on the event thread by main thread");
        try {
            SwingUtilities.invokeAndWait(r);
        } catch (InvocationTargetException | InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Main thread reached end");
    }
}

実行結果

JavaのSwingUtilitiesクラスとは?invokeAndWait()とinvokeLater()で実現するスレッドセーフなGUI操作

JavaのSwingUtilitiesクラスとは?invokeAndWait()とinvokeLater()で実現するスレッドセーフなGUI操作

このプログラムを実行すると、まずmainスレッドが3秒間スリープした後、Runnableオブジェクトがイベントキューに登録されます。invokeAndWait()を使用しているため、ボタンのテキスト変更処理がイベントディスパッチスレッド上で完了するまで、mainスレッドは待機します。実行ログを確認すると、ボタンを実際に変更しているのはイベントディスパッチスレッドであることが分かります。

まとめ

SwingUtilitiesクラスは、SwingアプリケーションにおいてスレッドセーフなGUI更新を実現するために不可欠なユーティリティです。UIコンポーネントの操作は必ずイベントディスパッチスレッド上で行う必要があり、invokeLater()による非同期実行とinvokeAndWait()による同期実行を使い分けることで、安全かつ安定したデスクトップアプリケーションを構築できます。

  1. JavaのGridBagConstraintsクラスとは?その役割と主なフィールドを徹底解説

    GridBagLayoutは、Java Swingで最も柔軟性の高いレイアウトマネージャーのひとつです。コンポーネント同士の相対的な位置関係を制約(constraints)を使って細かく指定できるのが最大の特徴です。GridBagLayoutは動的な矩形グリッド(セルの集まり)を内部に持ち、各コンポーネントは1つ以上のセルを占める「表示領域」に配置されます。そして、GridBagLayoutで管理されるすべてのコンポーネントには、その配置方法を定義するためのGridBagConstraintsインスタンスが関連付けられます。つまり、GridBagConstraintsは複雑なフォームレイアウト

  2. JavaのSwingWorkerクラスとは?GUIアプリで非同期処理を行う重要性と使い方を解説

    SwingWorkerクラスは、時間のかかる処理(長時間実行タスク)などをワーカースレッド上で非同期に実行し、その結果に基づいてイベントディスパッチスレッド(EDT)からSwingコンポーネントを安全に更新するための仕組みを提供します。このクラスはJava 1.6で導入されました。Swingでは、すべてのUI更新はEDT上で行う必要があります。しかし、EDT上で重い処理を直接実行すると画面がフリーズしてしまい、ユーザー体験を大きく損ないます。SwingWorkerを使えば、バックグラウンドでの処理とUIの更新を適切に分離できるため、応答性の高いデスクトップアプリケーションを実現できます。Swi