2016-11-22 24 views
1

私が知りたいのは、例えばr.wait()が動作するかどうかです。このコードでは:notify/wait()で特定の(グループの)スレッドを起床/中断するにはどうすればよいですか?

public class Buffer1<T> { 
private T content; 
private boolean empty; 
private Object r = new Object(); 
private Object w = new Object(); 

public Buffer1() { 
empty = true; } 

public Buffer1(T content) { 
this.content = content; 
empty = false; } 

public T take() throws InterruptedException { 
synchronized (r) { 
while (empty) { 
r.wait(); 
} 

synchronized (w) { 
empty = true; 
w.notify(); 
return content; 
    } 
} 
} 

public void put(T o) throws InterruptedException { 
synchronized(w) { 
while (!empty) { 
w.wait(); 
} 

synchronized (r) { 
empty = false; 
r.notify(); 
content = o; 
} 

はどのようにr.wait()、w.wait()、r.notify()、w.notify()動作しますか?そして、それらは同期(r)/同期(w)とどのように連携しますか?

+0

さて、あなたの人生は 'notifyAll()'によってもっとシンプルになるかもしれません...本当に特定のスレッドグループを起こすことは想定されていません。それは目を覚ます。このため、 'wait()'は常にループ内で発生するはずです。一度目を覚ますと、スレッド自体は目覚めさせるのが良いかどうかをチェックし、そうでなければ 'wait()'に戻ります。しかし、目覚めと通知は、並行プログラミングのための低レベルの構造であり、あなたは本当にコンカレントモジュールを簡単に構成するExecutor Frameworkの使用について考えるべきです。 – scottb

+0

あるいは 'java.util.concurrent'パッケージのセマフォーです。 – EJP

答えて

0

スレッドはグループに中断されません。スレッドが同期化されたブロックまたはメソッドに入り、ロック(ここではrまたはw)を取得し、ロックが獲得したオブジェクトでスレッドが呼び出しを待機した場合、そのスレッドは中断し、wait onと呼ばれるロックを解放し、そのロックの待機セットに追加されます。

ここに、待機する呼び出しを囲むループがあるパターンがあります。メソッドを呼び出すスレッドは、ループ内のテストが偽になるまで待たなければなりません。スレッドを待機させる状態を条件と呼びます。 waitメソッドは、主に通知されたスレッドにロックの所有権がないためループで呼び出されます。ロックを再度取得すると現在の状態をテストする必要があります。

ロックの待機セット内のすべてのスレッドは、そのロックに対してnotifyAllを呼び出すことによって起動します。実際には最適ではありません。通常、スレッドのうちの1つだけがロックを取得して一度に処理を進めるためです。 notifyAllの使用は、同じロックを競合するスレッドが異なる条件を待つことができ、一部のスレッドとは関係のない状態の通知が発生した場合に発生します。 notifyが使用されている場合、スケジューラーの気まぐれで選択された1つのスレッドだけが起動されます。スレッドが待機している状態が、通知があったものでない場合、通知は失われ、スレッドは進行しません。通知がいずれかのスレッドに適用可能な場合は、notifyAllを使用して、そのうちの1つが進捗することができます。他の待機中のスレッドがコンテキスト切り替えされて待機状態に戻るのを犠牲にしても、これは代替案よりも優れています。

投稿コードでは、notifyAllを各条件ごとに個別のロックオブジェクトを使用することで回避することが意図されています。オブジェクトrには、バッファが空でなくなるまで待機しているスレッドがあり、オブジェクトwには、バッファが空になるまでスレッドが待機しています。通知が呼び出されると、その通知が関連するスレッドをウェイクさせることが確実になります(入れようとするスレッドのみがw.notify()によって呼び起こされます)。

このコードの問題は、put操作とtake操作が両方のロックを取得し、互いの逆の順序でロックを取得することです。それはデッドロックを引き起こす本当に良い方法です。同期化されたキーワードと本質的なロックでは、タイムアウトとバックオフの方法はありません。復旧するには良い方法はありません。あるスレッドがrを持っていて、wが必要な場合、もう一方のスレッドがwを望んでいて、rが必要な場合は、あなたは立ち往生します。ロックを保持している2つのスレッドは処理を進めることができず、他のスレッドはロックを取得できないため、JVMを強制終了するまで、このバッファのメソッドをブロックしようとするスレッドが発生します。

関連する問題