7

JavaSwingのスレッドモデルが間違っていると何度も耳にしました。理由はよくわかりません。問題はDrawable、メインUIスレッド以外の別のスレッドから描画できるという事実に関連していることを知っています。のようなユーティリティ機能がSwingUtilities.invokeAndWaitありSwingUtilities.invokeLater、でペイントを実行できることを知っていますRunnable。これは、EventDispatcherスレッドによって実行されます。このようにして、ペイントが同期的に行われ、バッファが不整合な状態のままにならないようにすることができると思います。

私の質問は、「優れた」UIツールキットはどのように動作するのかということです。どのようなソリューションが採用されていますか?

4

4 に答える 4

9

Brian GoetzのJava同時実行の実際

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

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

于 2012-11-22T21:13:40.113 に答える
3

SWTの場合:http://book.javanb.com/swt-the-standard-widget-toolkit/ch05lev1sec7.html

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

したがって、SWTもシングルスレッドです。ただし、UIスレッドの外部でのUIへの変更を禁止するには、追加の手順が必要です。他の場所からUIを変更することは許可されているが、遅かれ早かれ予期しない結果を生成し、Swingが「ハード」な方法でシングルスレッド化されていることを学ぶ初心者プログラマーを混乱させるSwingの代替案を検討してください。

また、デザインが明確でない場合、正しいスレッドにいると思うが実際にはそうではないという状況に陥る可能性があります。また、どのスレッドが特定のコードにアクセスするかを確実に判断できない場合もありますが、いずれにせよ、自分のコードに重大な設計上の問題がある可能性があります。

それ以外に、Swingのスレッドモデルが「間違っている」と見なされる他の理由を想像することはできません。

于 2012-11-22T21:27:32.693 に答える
1

現在のディスプレイテクノロジーの実装方法では、画面上のピクセルのペイントは常にシリアルです。1秒間に約30枚の画像を生成し、それらを1つずつペイントする必要があります。

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

したがって、技術的には、EDTを使用して変更を送信する場合、Swingはスレッドセーフです。そして、それが目的でinvokeLater()あり、invokeAndWait()方法です。彼らはEDTに変更を提出します。

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

于 2012-11-22T20:57:45.100 に答える
0

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

別のスレッドを使用せずに、ユーザーが開始したイベントから長時間実行されるタスクを実行すると、問題が発生する可能性があります。問題は、タスクの実行中にアプリケーションがフリーズすることです。再描画は発生せず、ユーザーはすべてを操作できなくなり、アプリケーションがロックアウトされたように見えます。

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

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

于 2012-11-22T20:55:32.763 に答える