準・究極の選択

多くのサイトを見て、色々考えているのですが、イマイチ理解が及びません。以下のような風に思っていていいのでしょうか。

・Swingではメインとなるmainスレッド(表現は正しくないかもしれない)と、描画関係のイベントを実行するイベントディスパッチスレッドで出来てる。

・描画関係のイベント(正確にはコンポーネントの可視化及び可視化したコンポーネントの描画)はイベントディスパッチスレッド上で実行しなければならない。

・SwingUtilities.invokeLaterを使うことによってその中身のプログラムをイベントディスパッチスレッドで実行してくれる...?
→setVisible(true)やsetText("")など全てSwingUtilities.invokeLaterを使って記述しなければならない.....???(面倒すぎじゃないでしょうか)

・Swingでのマルチスレッドを行うにはSwingWorkerを使う(ことは見つけているのですが、まずEDTについて理解しないと先に進めないと思い、まだあまりこれの内容は調べていません)

・描画系の命令を実行しないのならば、別スレッドを作成して使用しても良い....?


こんなところでしょうか。
しかし、このとおりだとすると今までの自分の書いてきたプログラムは間違いだらけ(特に「全ての描画系命令をSwingUtilities.invokeLaterを使いEDTで実行する」点)になってしまいます。

ちゃんとした理解をしておきたいので、わかりやすい説明でも、上記の間違っている点でもご教示願います。

A 回答 (1件)

書いてあること自体は、一部を除いて、ほぼ間違っていないと思います。



ただ、自分の書いたコードがイベントディスパッチスレッドで動いているのかそうでないのか、よくわからなくて混乱されているような印象を持ちました。

Swingは、シングルスレッドの設計です。Swingコンポーネントに対する呼び出しは、イベントディスパッチスレッド(EDT)上で行われる必要があります。例外は、repaint()です。
マウス、キーボード操作などのイベントも、すべてEDT上で処理します。

アプリケーションの処理はイベントに対する反応として記述します。これが、イベント発生時に呼び出されます。イベントは1つのスレッド上で順番に処理されます。
こういう設計は、イベント駆動といって、プラットフォームを問わず、GUIを持つアプリケーション用の仕組みとして一般に見られるものです。
http://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%99% …

> Swingではメインとなるmainスレッド(表現は正しくないかもしれない)と、描画関係のイベントを実行するイベントディスパッチスレッドで出来てる。

Javaでmainスレッドというと、最初に作られるスレッドですが、mainスレッド自体はとくに必要無いので、終わってしまってもかまいません。実際、自分の作ったアプリケーションでも、用が済んだらmainスレッドはすぐに終了してしまいます。EDTが重要です。

ただ、シングルスレッドの設計とはいえ、Swingは、EDT以外のスレッドも内部で使用します。
例えば、java.awt.Toolkitで画像を読み込むとバックグラウンドのスレッドで読み込まれます。
画像の読み込みには一般的に時間がかかるからです。

> 描画関係のイベント(正確にはコンポーネントの可視化及び可視化したコンポーネントの描画)はイベントディスパッチスレッド上で実行しなければならない。

そうです。描画というより、Swingコンポーネント関係の操作をEDT上で行う必要があります。
コンポーネントの描画もEDT上で行われます。
可視化というのが何を指すのか、ちょっと意味がとれませんでしたが…
setVisible(true) のことでしょうか? ということなら、これもその通りです。

> SwingUtilities.invokeLaterを使うことによってその中身のプログラムをイベントディスパッチスレッドで実行してくれる...?

そうです。invokeLaterに渡したRunnableオブジェクトのrunメソッドを呼ぶというイベントが、イベントキューに入れられます。イベントが処理されるとrunメソッドが呼ばれます。
そのため、即座に実行されるわけではなく、実行が予約されるような動きであると思ってください。

> →setVisible(true)やsetText("")など全てSwingUtilities.invokeLaterを使って記述しなければならない.....???(面倒すぎじゃないでしょうか)

EDT以外から、setText等のSwingコンポーネントの操作をしたいのならその通りです。
しかし、マウス、キーボードイベントのようなイベント処理はそもそもEDT上で動くわけですから、そこでsetText等をする分には、invokeLaterを使っていなくても問題ないです。
そういう意味では、「全て」ではありません。あくまで、EDT以外のスレッドからの場合です。

> 面倒すぎじゃないでしょうか

すべてマルチスレッドで同期をきちんと考える面倒さと、全部をEDTでやる面倒さ、どっちが面倒か、ですね。
自分としては、用もないのにマルチスレッドで処理したくはありません。
マルチスレッドで、破綻無く動かすのはなかなか面倒です。

SwingWorkerについてですが、長時間の処理を実行したいとき、EDTで処理してしまうとイベントディスパッチループへ処理を返さないことになり、他のイベントを処理できなくなります。画面は固まって、応答なしになります。

となると、重い処理は別のスレッド(作業用スレッド)で実行したくなります。問題は画面へのアクセスです。プログレスバーのように、処理中の状況を画面に表示したいことがあると思います。しかし、EDT以外のスレッドからSwingコンポーネントにはアクセスできません。描画処理はイベントを送ってEDT側で処理する必要があります。
SwingWorkerは、この手の作業用スレッドとEDTとのやりとりや、作業スレッドの再利用など、面倒なところを助けてくれるものです。
便利ですが、使わなければいけないというわけではありません。ルールを守っていれば、自分で同じような仕組みを書けばいいので。でも、便利なので使いますけど。

> 描画系の命令を実行しないのならば、別スレッドを作成して使用しても良い....?

もちろんです。問題になるのは、描画系というかSwingコンポーネント関係です。
ただし、結果を表示したいとなったら、EDTに頼む必要があります。

見えないSwingの中でやっていることがいろいろあるので、なかなか、何がどこのスレッドで、どういうタイミングで動くのかイメージするのが難しいかもしれません。
    • good
    • 1
この回答へのお礼

細かく丁寧にありがとうございます。おかげで私の中で大きく勘違いをしていることに気づくことができました!!

今まで私はソースコードとして書いたプログラムをどのスレッドが行っているのか把握していませんでした。イベントリスナーによって実行されるプログラムなどはメインスレッドが行っているものだと思っていました。そのため理解に苦労していたのだと思います。

詳しい説明をありがとうございました! これからはSwingのスレッドポリシーに則ってプログラムを書こうと思います。

お礼日時:2014/04/23 15:58

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!