カウントセマフォを使用します。条件変数は、モニター内のスレッドをスケジュールするためのものです。これはあなたがやろうとしていることではありません。
カウントセマフォを作成し、カウントをゼロに設定します
// 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のモニターの定義とはまったく異なります。