DATE : 2006/04/02 (Sun)
Swing を使っていると、なぜかボタンなど GUI の反応が鈍いという現象が発生します。
Swing は比較的簡単にコードで GUI を作ることが出来ます。しかし、簡単だからといって適当に作ってしまうと落とし穴にはまってしまいます。
ここでは、その落とし穴の中から、GUI の反応が鈍い現象を取り上げてみます。
アプリケーションスレッドと AWT イベントディスパッチスレッド
通常、私達が組んだプログラムを実行するのは、アプリケーションスレッドと呼ばれるスレッドです。それに対して、Swing の処理は AWT イベントディスパッチスレッドというスレッドで行われます。
AWT イベントディスパッチスレッドは Swing の処理の他にも、ボタンが押された場合などのイベントリスナを呼び出す処理も行っています。
例えば次の execute メソッドは、action メソッドから呼ばれた場合はアプリケーションスレッドで、Swing によって actionPerformed メソッドから呼ばれた場合は AWT イベントディパッチスレッドで処理されます。
(このクラスは ActionListener を実装します)
public void action() {
execute();
}
public void actionPerformed(ActionEvent e) {
execute();
}
public void execute() {
// 処理
}
もしここで、execute メソッドの中で重い処理を行った場合はどうなるでしょうか。当然のことながら、 action メソッド、actionPerformed メソッドともに、メソッドが終了するまでにかなりの時間がかかります。
Swing が actionPerformed メソッドを呼び出せば、execute メソッドが終わるまでの間、 Swing の処理が止まります。
重い処理は別のスレッドで
そのため、 AWT イベントディスパッチスレッドで実行される可能性のある処理は、速めに終えなければなりません。
具体的には、処理の中でスレッドを生成して、重い処理はそのスレッドの中で行うようにします。
(このクラスは ActionListener を実装します)
public void action() {
execute();
}
public void actionPerformed(ActionEvent e) {
Thread t = new Thread(new Runnable() {
public void run() {
execute();
}
});
t.start();
}
public void execute() {
// 処理
}
このようにすれば、AWT イベントディスパッチスレッドはスレッドを実行した直後に終了し、Swing の処理が再開されます。
ただし、今回の例のように別々のスレッドから同じメソッドが呼ばれるような場合は、何かしらの排他制御を行う必要がでてくるかもしれません。
参考文献
- How to Use Threads(英語)(;^ω^)ほとんど読んでいませんが