yuu_nkjm blog
2011-05-19(Thu) 編集
[Java][Swing] イベントディスパッチスレッド以外のスレッドからのイベントディスパッチスレッドへのアクセス
概要
イベントディスパッチスレッド(EDT)とは別のスレッドで,重たい計算をさせたい.しかし,Swingのコンポーネントに影響を与える処理を外部のスレッドで行うことはできない.外部からイベントディスパッチスレッドに処理を依頼するときは,SwingUtilities.invokeLaterを用いる.
分かりやすい例
時間のかかる処理を行った後、最後にSwingUtilities.invokeLater()を呼び出しています。これは、「toDoListModel.remove(int index);」および「setButtonsEnabled(true)」の2つの処理をイベントディスパッチスレッドで実行させるために使っています。なぜ、わざわざこのようなことをするのでしょうか?
Swingのスレッドポリシーとして、次のようなものがあります。
「コンポーネントの「状態に依存する」あるいは「状態に影響を与える」 処理はすべてイベントディスパッチスレッド上で動作しなければならない」
これはいい換えると、Swingの描画に関連する処理は、シングルスレッドで処理しなくてはならないということです。そして、そのシングルスレッドがイベントディスパッチスレッドなのです。このルールにのっとるため、わざわざSwingUtilities.invokeLater()を使っているのです。
Swingライブラリのソースコードとサンプル
(snip) public class SwingUtilities implements SwingConstants { (snip) /** * doRun.run() を、AWT イベントディスパッチスレッドで非同期的に実行させます。 * これは、保留中のすべての AWT イベントが処理されたあとに発生します。 * このメソッドは、アプリケーションスレッドが GUI を更新する必要がある * ときに使用されます。次の例では、invokeLater 呼び出しは * イベントディスパッチスレッドに Runnable オブジェクトの * doHelloWorld のキューを呼び出してから、メッセージを出力します。 * * * Runnable doHelloWorld = new Runnable() { * public void run() { * System.out.println("Hello World on " + Thread.currentThread()); * } * }; * * SwingUtilities.invokeLater(doHelloWorld); * System.out.println("This might well be displayed before the other message."); * * invokeLater がイベントディスパッチスレッド、たとえば JButton の * ActionListener から呼び出された場合、doRun.run() は保留中のすべて * のイベントが処理されるまで実行が延期されます。ただし、doRun.run() * がキャッチされない例外をスローする場合は、イベントディスパッチスレッド * (現在のスレッドではない) が状態を元に戻します。 * * このメソッドの追加のドキュメントと例については、「The Java Tutorial」の * * 「How to Use Threads」を参照してください。 * * JDK Version 1.3 以降、このメソッドは java.awt.EventQueue.invokeLater() * を呼び出すだけです。 * * このメソッドは、ほかの Swing のメソッドとは異なり、どのスレッドから * でも呼び出せます。 * * @see #invokeAndWait(Runnable) */ public static void invokeLater(Runnable doRun) { EventQueue.invokeLater(doRun); } (snip)Oracle Java 1.6 SwingUtilitiesクラスソースコードより