7

私は2つのスレッドを起動するアプリケーションを持っています.1番目は別のクラスを起動して処理を行い、次に3番目のクラスを起動してさらに処理を行います。メイン クラスの 2 番目のスレッドは、ジョブを実行する前に、3 番目のクラスのイベントが完了するまで待機する必要があります。これはどのように達成できますか?

2 つのスレッド間でロック オブジェクトを共有するために待機/通知を実装しようとしましたが、難しい方法を見つけたため、技術的には機能しません。クラス間でロックを共有できますか? 3 番目のクラスのインスタンスは 1 番目のクラスで宣言され、パラメーターとして 2 番目のクラスに渡されることに注意してください。また、イベントがいつ完了したかを示すブール値を3番目のクラスで作成してから、この値がtrueになるまで2番目のスレッドをポーリングしようとしました。これは機能しましたが、あまり望ましくありません。また、actionListner はこの問題に対するより良いアプローチですか?

4

5 に答える 5

10

どのような問題が発生しましたか? あなたが説明したように、それはうまくいくはずです。たとえば、インスタンスをロックとして使用して、1 つのクラスからチェックされ、他のクラスから設定されるフラグを保持する 3 番目のクラスに 2 つのメソッドを実装できます。

boolean done = false;

public synchronized setDone() {

    done = true;

    this.notifyAll();
}

public synchronized waitUntilDone() {

     while (!done) {

        try {
             this.wait();

        } catch (InterruptedException ignore) {
             // log.debug("interrupted: " + ignore.getMessage());
        }
     }
}

(注: メモリから入力され、Java コンパイルを使用してチェックされていません)

原則としてthis.、wait と notifyAll の前は必要ありません。この状況にそれらを含める方が明確です。

于 2010-05-08T10:15:01.973 に答える
4

カウントセマフォを使用します。条件変数は、モニター内のスレッドをスケジュールするためのものです。これはあなたがやろうとしていることではありません。

カウントセマフォを作成し、カウントをゼロに設定します

// create a counting semaphore with an initial count of zero
java.util.concurrent.Semaphore s = new java.util.concurrent.Semaphore(0);

セマフォをクラスに渡し、処理を行います。終了したら、を呼び出してカウントを1に増やしs.release()ます。

プロセッサが終了するまでスレッドをブロックするには、を呼び出しますs.aquire()。その呼び出しにより、プロセッサがを呼び出すまで、他のスレッドがブロックされますs.release()

これが最も簡単な解決策です。

ところで、s.aquire()スレッドs.release()セーフなので、synchronizeキーワードを使用する必要はありません。スレッドは、セマフォへの参照を共有し、ロックせずにそのメソッドを呼び出すことができます。

アップデート:

新しいコメントをする代わりに、ここであなたのコメントに返信します。

はい、あなたの場合、wait()/ notify()ソリューションはセマフォの使用に似ています。rspのソリューションをセマフォで書き直すと、次のようになります。

java.util.concurrent.Semaphore s = new java.util.concurrent.Semaphore(0);

public setDone() {
    s.release();
}

public waitUntilDone() {
     s.aquire();
}

これははるかに簡単で、不要なロックは必要ありません(syncedキーワードをメソッドdecsから削除したことに注意してください)。

条件変数(wait()/ notify())とセマフォには2つの違いがあります。

違い#1:notify()の呼び出しが失われる可能性があり、release()の呼び出しが失われることはありません

最初の違いは、wait()の呼び出しを介して待機しているスレッドがない場合、notify()の呼び出しが失われることです。回避策は、wait()を呼び出す前に条件を確認することです。基本的に、notify()が共有変数で呼び出されたため、ワーカーがnotify()を呼び出した後に誤ってwait()を呼び出さないようにする必要があります。そうしないと、デッドロックが発生します。カウントセマフォは、内部でカウントを維持するため、acquire()とrelease()が呼び出される順序に関係なく機能します。

違い#2:wait()の呼び出しは自動的にロックを解除しますが、acquire()の呼び出しはロックを解除しません

ここでは、いくつかの背景情報が役立ちます。プログラムでは、boolean done = false; 変数は条件ですが、条件変数ではありません。紛らわしい用語、私は知っています。条件変数は、wait()およびnotify()操作を持つ変数です。Javaのすべてのオブジェクトには、内部に隠された条件変数と対応するロックがあります。

すべての条件変数はロックに関連付けられています。wait()とnotify()を呼び出す前に、ロックを取得する必要があります(取得しない場合は、ランタイム例外が発生します。試してみてください)。ロックが取得されると、wait()を呼び出すと自動的にロックが解除され、モニター内の別のスレッドがnotify()を呼び出すことができるようになります。場合によっては、これがまさにあなたが望むものであり、セマフォを使用してこの動作をシミュレートしようとすると、はるかに複雑になります。

注:私はモニターのアカデミックな定義を使用していますが、これはJavaのモニターの定義とはまったく異なります。

于 2010-05-10T06:39:43.963 に答える
4

Use a CountDownLatch with an initial value of 1.

Make the 3rd class call countDown() once processing is complete. The calling thread can then call await(), which will block until processing is complete.

于 2010-05-08T10:23:37.397 に答える
4

ActionListener解決しようとしている問題は、共有を使用するか使用することで簡単に解決できますQueue

キューに何かが現れるまでコンシューマーをブロックするブロックキューを選択するだけです。シンプルで明確、そして実績があります。

さらに必要な場合は、http://akkasource.org/またはhttp://jcp.org/en/jsr/detail?id=166(Java 7にデフォルトで含まれます)のようなプロジェクトを調べください

于 2010-05-08T10:40:58.957 に答える
0

join()操作はこの目的に適していると思います

図:

2つのスレッドがあるとしましょう

thead1 -> 待機する必要があるスレッド。

thread2 -> thread1 が待機するスレッド。

次に、スレッド1のコードで、待機したい場所に次のように記述します

thread2.join()

お役に立てれば!

于 2013-11-26T05:17:13.623 に答える