EDT とメインスレッド間の通信
-
09-09-2019 - |
質問
最近取り組んでいるプロジェクトについて、たくさんの質問をしました。これが私がいるシナリオであり、正しい方向への助けや指摘があれば、非常に役立つでしょう...
これは、サーバーと複数のクライアントで構築されたネットワーク プログラムです。各クライアントには GUI があり、サーバーから送信されたコマンドに従って動作する必要があります。各クライアントは というクラス内にラップされます。 Player
. 。これ Player
GUI を備えています (拡張 JFrame
) と main メソッドがあり、サーバーには main メソッドのみ (GUI はありません) があります。最初に、このクラスは次のようにメインスレッドで作成されました。
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Player().setVisible(true);
}
});
これは問題なく機能していましたが、全体が Player
クラスは EDT で実行されるようになりました。そのため、サーバーからのコマンドを待機すると、そのコマンドが送信され、適切なアクションが実行されるまで、GUI 全体がロックされます。ご想像のとおり、これはひどい設計であり、何かをチェックするたびに GUI をそのまま維持するためにクレイジーな回避策を見つけなければならないコーディング環境にとっては非常に面倒な作業であることがわかりました。
明らかに、サーバーからのコマンドを別のスレッドでチェックし、EDT で GUI コンポーネントを実行する必要があります。私の 2 番目の実装には 2 つのクラスがありました。1 つは GUI 用、もう 1 つは Player
. 。そのアイデアは、 Player
GUI を保持する変数があったので、 Player
クラス、次のようなもの:
class Player
{
public GUI gui;
...
// And then start this gui inside of the EDT.
EventQueue.invokeLater(new Runnable()
{
public void run()
{
this.gui = new GUI().setVisible(true);
}
}
これも機能しません。 this
新しいのの中 Runnable
オブジェクトとは、 Runnable
オブジェクトではなく、 Player
.
間で通信するにはどうすればよいですか Player
クラスを 1 つのスレッドに配置し、対応する GUI クラスを EDT スレッドに配置しますか?
他のヒント
this
ポインタを使用して問題に対処するには、次のように記述する必要があります:
class Player
{
public GUI gui;
...
// And then start this gui inside of the EDT.
EventQueue.invokeLater(new Runnable()
{
public void run()
{
Playser.this.gui = new GUI().setVisible(true);
}
}
}
ボリス・パブロビッチは、構文を右に(実際にはあなただけthis.
を削除することができ)取得しますが、まだコードは意味がありません。 gui
イベントがキューイングされた後Runnable
フィールドはいつか初期化されるので、プレイヤーのスレッドがそれを使用することが安全ではありません。
あなたは、EDT上Player
を構築する(ただし、EDTオフネットワーク運用を行う)ことができます。またはPlayer
のリスナー(オブザーバー)としてGUIを登録します。 invokeAndWait
は動作しますが、それは多くの場合、時折困難なデバッグデッドロックにつながるように危険であるでしょう。
あなたはこれを試すことがあります:
クラスのプレーヤー { 公共のGUI GUI;
...
// And then start this gui inside of the EDT.
EventQueue.invokeLater(new Runnable()
{
public void run()
{
Player.this.gui = new GUI().setVisible(true);
}
}
「私は全体のプレーヤーのクラスは今EDTで実行していたことを実現するまで」
コンストラクタは、EDT上で発生するが、このクラスで呼び出されるメソッドは、ではないかもしれません。
あなたが最初に意図したように、あなたはプレーヤーのGUIを構築する必要があります。
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Player().setVisible(true);
}
});
しかし、プレーヤーは(個人的に私は選手間の接続を共有したいと)コンストラクタで別のスレッドを起動することができます。
可視コンポーネントを変更する場合、もちろん、サーバからのコールバックメソッドは、invokeLater()を使用する必要があります。
の代わりに匿名の内部クラスを使用するのは、なぜ単に道具のRunnableクラスを宣言し、引数としてGUIインスタンスを取るコンストラクタを持っていませんか?
あなたのGUIクラスはスレッドセーフされていない場合は、また、EDT&メインスレッド間の通信にメッセージキューを使用することを検討します。