Swing (およびほぼすべての GUI ツールキット) には専用のスレッドがあります。このスレッド (イベント ディスパッチ スレッド) は、最初に必要になったときに開始されます。これは通常setVisible
、JFrame
. このスレッドは巨大なループであり、その役割は入力イベントを消費してイベントを再描画し、それに応じていくつかのロジックを実行することです。
あなたの場合、実際には 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 とスレッドを組み合わせる際には考慮すべきことがたくさんあります。他のオプションが何であるかを理解するのに役立つことを願っています.