2012-11-22 4 views
7

Java Swingのスレッドモデルが間違っていると聞きました。なぜ私は、あなたがメインのUIスレッド以外の別のスレッドからDrawableを引き出すことができるという事実に関連していることを十分に理解していません。 Runnableで絵を描くことを可能にするSwingUtilities.invokeAndWaitSwingUtilities.invokeLaterのようなユーティリティー機能があり、これはイベントディスパッチャースレッドによって実行されることが分かります。私はこの方法で、ペインティングが同期して行われることを保証しています。これは、バッファーが不安定な状態にならないようにします。スイングスレッドモデルが間違っていると考えられる理由は何ですか?

私の質問はです:「良い」UIツールキットはどのように振る舞いますか?採用されているソリューションは何ですか?

+0

私はなぜこの質問をd​​ownvote ...知っていると思いますが何が間違っている? – gotch4

+4

upvoteを持っています。あなたの質問は大丈夫だと思います。 –

+2

あなたは聞いた場所の参照をリンクすることができますか? – Axel

答えて

9

ブライアン・ゲッツのJava Concurrency in Practice

9.1はなぜシングルスレッドのGUIがありますか?

...昔、GUIアプリケーションはシングルスレッドであり、「メインイベントループ」から処理された GUIイベント。最新のGUIフレームワークでは、わずかに異なる モデルが使用されます。GUIイベントを処理する専用のイベント ディスパッチスレッド(EDT)を作成します。シングルスレッドのGUI フレームワークはJavaに固有のものではありません。 Qt、NextStep、MacOS Cocoa、X Windowsなど、他の多くのものもシングルスレッド化されています。これは試していないので、 のためではありません。多くの試みがマルチスレッドの GUIフレームワークを記述してきましたが、レース 条件とデッドロックの問題が永続的に発生したため、最終的に シングルスレッドイベントキューモデルに到達しました。アプリケーション定義のイベント ハンドラにそれら... SWTのために

+0

もう1つの質問は、invokeAndWaitとinvokeLaterの代わりに、BEGIN_DRAWメソッドとEND_DRAWメソッドのペアで描画呼び出しを囲むアプローチを使用しないようにして、並行処理を行う理由です。私はこれをOGLなどで見てきました。 – gotch4

+0

@ gotch4これらのメソッドは実際には 'Runnable'でアクションをカプセル化し、' EventQueue'でポストして、 'EventDispatchThread'で利用できるようにします。これらのアクションはEDTで実行されます。あなたが提案したメソッドで素朴な境界を使用すると、それらの間にあるすべてのものがこの現在のスレッド(EDTではなく)で実行されます。 –

0

スイングには、基本的にユーザーがアプリケーションのグラフィカルな部分と対話できるようにするスレッドがあります。ユーザーが開始したイベントに応じてクイックタスクのみを実行する場合、アプリケーションは常に応答します。

ユーザーが開始したイベントから長期実行タスクを実行し、そのタスクを実行するために分離されたスレッドを使用せずに問題が発生する可能性があります - タスクの実行中にアプリケーションがフリーズする問題があります。再塗りつぶしは発生しません。ユーザーはそのすべてとやりとりすることができず、アプリケーション自体がロックされたように見えます。

タスクを分離したスレッドで実行している場合(たとえば、ページをダウンロードしていて、ダウンロードが完了したことをユーザーに通知したい場合)、そのタスクからSwingを直接更新することはできませんあなたの質問に記載されているヘルパーメソッドの1つを使用する必要があります。

これらのタスクを作成してアプリケーションが常に応答するようにするのは、より労力を要するプロセスですが、長い時間がかかります(ファイルのダウンロードが良い例です)。タスクが実行されている間でも応答することができ、タスク自体が許す限り、ユーザーがタスクをキャンセルできるようにすることもできます。モーダルダイアログを使用して、タスクが実行されている間に他の操作を行わないようにすることができます。そうしたい場合は、スピンホイールなどの進行状況ダイアログを表示できます。しかし、私は重要なことは、アプリケーションが何の理由もなく "凍結"しているとユーザに考えさせるものではないと思います。

+0

答えをありがとう、しかしこれは私が多かれ少なかれ知っていた部分です:私は問題が他のUIシステムでどのように取り組んでいるのか知りたいです – gotch4

+0

@ gotch4彼らはそれを別々に扱わない。彼らはそのすべてのもののように動作します。 – nos

1

現在の表示技術が実装されている方法は、画面上にピクセルをペイントすることは常にシリアルです。 1秒間に約30枚の画像を生成し、1枚ずつ塗りつぶす必要があります。

したがって、バックグラウンドでいくつかの同期を行う必要があるため、このペイントはマルチスレッドにする必要はありません。これは実際にSwingがやっていることです。イベントディスパッチスレッドと呼ばれる特別なスレッドを使用して、すべての変更が次のイメージの前に発生するようにスケジュールします。

技術的には、EDTを使用して変更を送信する場合は、スウィングはスレッドセーフです。そしてそれはinvokeLater()invokeAndWait()の方法のためです。彼らはEDTに変更を提出する。

ボタンを押した後に値を計算するなど、EDTを使用せずに長時間実行された変更を送信すると、アプリケーションが応答しなくなり、再描画されないことがわかります。 EDTはあなたの計算を忙しくしているので、再ペイントや他のイベントをスケジュールする時間がありません。

3

http://book.javanb.com/swt-the-standard-widget-toolkit/ch05lev1sec7.html

SWTは通常、アパートメントスレッドと呼ばれているシングルスレッドのユーザインターフェースモデルを実装しています。このモデルでは、ユーザーインターフェイスのスレッドのみがユーザーインターフェイスの操作を呼び出すことができます。このルールは厳格に強制されます。ユーザーインターフェイスのスレッドの外側からSWTオブジェクトにアクセスしようとすると、SWTException( "無効なスレッドアクセス")が表示されます。

だから、SWTもシングルスレッドです。しかし、UIスレッドの外部でUIに対する変更を禁止するには、余計な手順が必要です。別の場所からUIを変更することは許可されていますが、遅かれ早かれ予期しない結果が生成され、初心者のプログラマを混乱させ、スイングがシングルスレッドの「ハード」な方法であることを知ることができます。

また、デザインが明確でない場合は、正しいスレッドになっていると思われる状況になる可能性がありますが、実際にはそうではありません。いずれのスレッドが特定のコードにアクセスするのかを確実に伝えることができない場合もありますが、とにかく自分のコードに深刻な設計上の問題がある可能性があります。

それ以外は、Swingのスレッドモデルが「間違っている」と考えられる理由は他にもありません。

+0

SWTは別のスレッドがUIを混乱させていることをどのように検出できますか?すべてのツールキットメソッドがプロキシされ、チェックが行われていますか? – gotch4

+0

エラーのスタックトレースはプロキシを表示せず、orgのような何かをチェックしていることを示す名前のメソッドから例外が発生していることを示しているので、私はSWTに慣れていないので、わかりません。 eclipse.swt.widgets.Display.checkDevice。実際には、すべてのメソッドが例外をスローするわけではありません。これらのユーザーは、値がERROR_THREAD_INVALID_ACCESSのSWTExceptionをスローする可能性があると文書化されます。 –

+0

これは、[この記事](http://weblogs.java.net/blog/alexfromsun/archive/2006/02/)で説明されているように、カスタムRepaintManagerを使用すると、JavaFXと同じ方法でこれを確認できます。 debugging_swing.html) – Robin