2009-09-15 8 views
6

私は主に、EclipseでUI開発を行ってきました。これはスレッドアクセスの点で非常に控えめです:UIウィジェットの外からUIウィジェット(例えば、色、テキスト)上のプロパティを変更しようとする試み例外。Swingのスレッドポリシーに違反するとどうなりますか?

私は現在、多数のカスタムウィジェットを持つウィンドウを持つSwingの既存のプログラムを見ています。これらのウィジェットのそれぞれに対して突然変異関数を実行する別個のスレッドがあり、突然変異関数はいくつかの値(例えば、ラベルの色および値)を読み取り、いくつかを書き込む(例えば、背景色を変更する)。カスタムペインティングが関与していない、またはそのようなものはないことに注意してください。それに含まれるサブウィジェットには、ほとんどがJLabelです。

現在のところ、これは別のスレッドから実行され、Swingイベントスレッドからは実行されません。このスレッドは、すべての400ウィジェットを処理し、それぞれのウィジェットを呼び出します。更新は正しく動作するようですが、GUIはユーザー入力に応答しません。

スイングスレッドの外側から約0.4ミリ秒間実行され、invokeLaterまたはinvokeAndWaitのミューテータへのすべての呼び出しをラップすると、UIは非常に反応します。

私が理解しようとしているです:

1)が、それは時々正当なSwingのスレッドの外から、これらすべての電話をかけることですか?

2)Swingスレッドにどのような影響があり、外部から呼び出したときにUIが応答しにくいのはなぜですか?

答えて

3

"何もない"から断続的な問題まで、 "すべてが壊れた、GUIで作業するために全員を引き離す!"

主な(最も明白な)視覚効果は、GUIスレッドを保持すると(誰かがボタンを押してスリープ(5000)など)、GUIが再描画されないことです。それはあなたに渡すことが許されている唯一のスレッドを保持しているので、それはできません!これにより、人々はJavaが本当に遅いと思うようになります。悪くはありませんが、このような調査実習を気にしない多くの人が船積み製品を生産していることをプログラムするのは簡単です。

次に大きな問題は、別のスレッド(メインに渡されたものなど)で画面を描画しているときに、奇妙な動作をする可能性があることです。あなたのフレームをどのようにレンダリングするかについて、スウィングはあまりにも気が散っています。

最後に、まれに(間違ったスレッドでタイトなループでスイングコンポーネントを呼び出している場合)、スレッドの衝突を招くことはほとんどありません。それが起こった場合、例外がスローされる(またはスローされる)可能性があり、おそらく何かが間違ってレンダリングされるかもしれませんが、それは明白ではありません。

1

基本的な問題は、スレッドセーフではないオブジェクトがマルチスレッド形式で実行されることです。 HashMapのような単純なものであっても、無限ループで捕まえることができます。 AWTはロックを使います(ひどく)ので、デッドロックで終わる可能性もあります。しかし、更新されたバージョンのJavaが突然一部の顧客のマシンで問題を引き起こすことがあるかもしれませんが、あなたはそれを取り除く可能性があります。

(BTW:。それはAWTのイベントディスパッチスレッドだ、のスイングではない)

1

(1)については、画面上のピクセルがEvent Dispatching Thread (EDT)から呼び出されなければならない更新親指何のルールとして。何らかのJVMがEDTの外部からのアップデートを受け入れることができる場所では、この作業に決して頼るべきではありません。いくつかのマシンと異なるルックアンドフィールはうまく動作しません。この動作は未定義であり、これはあなたが見た応答性の欠如を説明することができます。

3

1)これらの呼び出しをすべてSwingスレッドの外部から行うのは正当なのですか?

いくつかの例外があります(例えば、テキストフィールドのテキスト値を設定すると自動的にEDTプロキシ処理が行われます)。はありません。状況がある方が良い場合があります。多くの更新を行っている場合は、個々の呼び出しではなく、1回のEDT呼び出し(invokeLater())を使用してすべてを行うことができます。長くて短く:EDTからのSwingコンポーネントに対する操作を実行します。これには読み書きが含まれます。

2)Swingスレッドにどのような影響があり、外部から呼び出したときにUIが応答しにくいのはなぜですか?

まあ、EDTはGUIの更新を担当しています。あなたが外部から電話すると、それほどレスポンスが悪くはありません。ユーザーインターフェイスを更新する実際の低レベルのシステムコールはまったく発生していないということです。あなたのアプリでおそらく起きていることは、元の開発者がスイングコンポーネントで本当に不快な競合状態を発生させずに幸運で変化する状態になっているということです。その後、EDTで再描画が発生し、コンポーネントが更新されます。これは「レスポンスの欠如」と思われるかもしれませんが、本当に起こっているのは「画面のリフレッシュが不足しています」ということです。

EDTはちょうど普通のスレッドですが、GUI関連の信号を処理するタイトなループで実行されるという点で少し特殊です(例えば、描画コマンド)。これらのタイプのコマンドをEDTに投稿するというセマンティックは、Javaスレッド(メッセージポンプへの操作の提出)とはまったく違っています。

- 「EDT上のSwingオブジェクトとのみ対話する」と言われるすべてのJavadocは、理由があるため記述されています。それを台無しにしないでください。バックグラウンド処理を行いたい場合は、J *コンポーネントとのやりとりをEDTにプロキシする必要があります(最も一般的にはinvokeLater()を使用します)。

2
  1. 実際に例外はありません。 Kevinは部分的に正しいです - JTextComponent.setText()はスレッドセーフとして宣伝されます。しかし、1.6コードを見ると、それはドキュメントオブジェクトの同期を提供し、EDTを使用しません。別のスイングコンポーネント(またはスイングコンポーネントを制御するもの)がドキュメントオブジェクトをリッスンしている場合を除き、これは問題ありません。ケビン氏の言うように、実際には(私が知っている)そうでない状況はありません。

  2. コードを掘り下げることなく言うのは難しい。その動作は未定義です。あなたのバックグラウンドタスクが長時間(>数秒)実行されていた場合、EDTを使用すると、タスクの実行中にUIが応答しなくなります。

幸運なことに、幸いなことに、それは正しい方法がとにかく効果的です。 :)

日は、実現されていないコンポーネントと他のスレッドを使用しても大丈夫だったと言うために使用されるが、後に撤回:

Related stackoverflow question

チェックアウト日のUIのチュートリアルをスイングし、同時実行(I上リンクを投稿するが、これは私の最初の答えはstackoverflow0です。

関連する問題