1

GUIアプリを完成させました。4 つのクラスがありますMain, UserWindow, Task1, Task2Mainクラスにはブール変数が含まれていますbuttonStartPressedMainメソッドはクラスのインスタンスを開始しUserWindow、ユーザーが [開始] ボタンを押すまで待機します。ユーザーが [開始] ボタン ( 内UserWindow) を押すと、 が にActionListener割り当てtrueられstatic boolean buttonStartPressedMainメソッドが続行されます。

Main.java

public static void ......
static boolean buttonStartPressed = false;

...........

while (!buttonStartPress) {
Thread.sleep(50);
}

Task1 t1 = new Task1();

.....
}
}

それはうまくwhileいきますが、私はループが好きではありません。これは、従来のアプリケーションの書き方ではないと思います。Main別の方法があります: クラスとUserWindowクラスを組み合わせることができ、 ActionListener(buttonPressed) の結果が Task1 の開始になります。しかし、その一方で、MainクラスとUserWindowクラスは互いに分離されるべきだと思います。

4

2 に答える 2

3

ええ、それは間違っています。ビジー ループがあるべきではありません....どこにも。

buttonStartPressed 変数も必要ですか? ボタンが押されたかどうかを知ることに興味があるのはなぜですか。ボタンが押されたときに何らかのアクションを実行することが主なアイデアではありませんか?

メソッドでTask1 を作成し、actionPerformed()何をしようとしているかに応じて、タスクを実行するスレッドを開始する必要があります (または、非常に高速な場合は EDT で実行するだけでフリーズしません)。 GUI)。

于 2013-10-03T18:10:22.290 に答える
2

Swing (およびほぼすべての GUI ツールキット) には専用のスレッドがあります。このスレッド (イベント ディスパッチ スレッド) は、最初に必要になったときに開始されます。これは通常setVisibleJFrame. このスレッドは巨大なループであり、その役割は入力イベントを消費してイベントを再描画し、それに応じていくつかのロジックを実行することです。

あなたの場合、実際には 2 つのスレッドがあります。1 つ目はmainスレッドで、2 つ目はEDT. あなたのmainスレッドはビジー待機中です。ユーザーがボタンを押すとすぐに、コードactionListenerが実行されます。EDT

2 つのスレッドを通信させる方法としてブール変数を使用しています。いくつかの共有メモリを使用することは、実際にスレッド間通信を行う 1 つの可能な方法です。

さて、ご想像のとおり、忙しい待機を避ける必要があります。CPU 時間を無駄に消費し、ウェイクアップするたびに他のスレッドを妨害し、避けられない反応遅延があります。

共有メモリを使用した通信も一般的に悪いです。これはあまりにも低レベルなコミュニケーション方法であり、しばしば間違った方法で行われます。2 つのスレッドからのデータへのアクセスは、ロック メカニズムによって保護する必要があります。ブール値のような単純なデータでさえ、1 つのスレッドがそのデータに書き込みを行った場合に、もう 1 つのスレッドがその変更を確認できるという保証がないため、問題が発生する可能性があります。あなたの例では、ブール値は少なくともvolatileこの保証を持つように宣言する必要があります。

したがって、volatileキーワードを追加すると、ソリューションが機能します。EDT喜んで自分の仕事をしているユーザーがいて、ユーザーがボタンをクリックすると、mainスレッドが実行されTask1ます。自問する最初の質問はTask1、時間のかかる作業ですか? 実際、最も簡単な解決策は、 Task1 をEDTから呼び出して で実行することactionListenerです。EDTでコードを実行すると、GUI がフリーズすることに注意してください。Task1持続時間が 100 ミリ秒未満の場合、ユーザーはフリーズに気付かず、別のスレッドで実行しても意味がありません。GUI クラスを「タスク」クラスと結合することに不安がある場合は、オブザーバー パターンを使用して、直接的な依存関係を回避する必要があります。

タスクに時間がかかり、GUI をフリーズさせたくない場合は、複数のスレッドを使用する必要があります。1 つの解決策は、実装したものです。mainスレッドが 1 つしかないため多少制限がありますが、機能します。あなたの問題は、これらのスレッドを通信させることです。スレッド間通信の非常に一般的なパターンは、ブロッキング キューを使用することです。これも共有データですが、複数のスレッドで使用できるように設計されています。一方のスレッド ( EDT) が書き込み ( add())、もう一方のスレッドが読み取り ( )take())、何かが書き込まれるまでブロックします。これは単純な例ではやり過ぎに思えるかもしれませんが、スレッド間でデータを共有するための非常に便利な方法です。ブロッキング キューに書き込まれるオブジェクトは何でもかまいません。たとえば、実行するコマンドを表すことができます。

時間のかかる関数を GUI から実行する従来の方法は、必要に応じて専用スレッドを作成または使用することです。これは、低レベルの API ( Thread ) または高レベルの API ( ExecutorService ) を使用して行うことができ、どちらも非常に使いやすいです。ここでも、スレッドの作成から GUI アクションを切り離したい場合は、observer パターンを使用してください。

このテキストの壁があなたの質問に対する簡単な答えを提供していない場合は申し訳ありませんが、GUI とスレッドを組み合わせる際には考慮すべきことがたくさんあります。他のオプションが何であるかを理解するのに役立つことを願っています.

于 2013-10-03T23:28:26.907 に答える