2011-12-15 4 views
1

「追加」メソッドと「取得」メソッドには、最初のスレッドがデータを追加し、2番目のスレッドがデータを取得するいくつかのブロック機構を持つキューがあります。上記のコードでデッドロックの待機/通知

public synchronized MyObj getData() {    
    synchronized (myLock) { 
     synchronized (this) { 
      if (isEmpty()) {     
       wait(0);      
      } 
     }  


     return getData();   
    } 
} 

public synchronized void addData(MyObj data) { 
    if (!isFull()) { 
     putData(data); 
     synchronized (this) { 
      notify(); 
     } 
    } 
} 

、最初のスレッドがデータを取得しようとすると、キューが空である場合、私は待機を経て、待機中に入れた(0)他のスレッドまで通知()を経由して待ってからリリースをキューにデータを追加します。

今、私はキューがいっぱいになると、いくつかのいずれかがそれにデータを追加しようとしたときに、別の「ロック」を追加します:結果は、私が期待するものではありません

public synchronized MyObj getData() {    
    synchronized (myLock) { 
     synchronized (this) { 
      if (isEmpty()) {     
       wait(0);      
      } 
     }  

     synchronized (this) { 
      notify(); 
     } 
     return getData();   
    } 
} 

public synchronized void addData(MyObj data) { 
    synchronized (myLock) { 
     synchronized (this) { 
      if (isFull()) { 
       wait(0); 
      } 
     } 
    } 

    synchronized (this) { 
     notify(); 
     } 
     PutData(data); 
} 

、私は私が死んを得ることを推測しますロック原因プロセスが停止しています。

UPDATE

これは私がデータを取得する方法である:

queueSize--; 
startPointer = (startPointer + 1) % mqueueSize; 
data = (String) queue[startPointer]; 

これは私はあなたがjava.util.BlockingQueueで見ていないのはなぜ

queueSize++; 
    endPointer = (endPointer + 1) % mqueueSize; 
    queue[endPointer] = data; 

public synchronized boolean isEmpty() { 
     return queueSize== 0; 
    } 

    public synchronized boolean isFull() { 
     return queueSize== mqueueSize; 
    } 

答えて

1

データを追加する方法です。おそらくそれはあなたの状況で役に立つでしょう。

は特にあなたは、コンストラクタでキューの容量を指定した場合、そのキューはブロックしますjava.util.LinkedBlockingQueue、見てみましょう。

+0

2の理由、 – kenny

1

メソッドシグネチャから​​キーワードを削除してください。これは、synchronized(this)ブロックが単に冗長であるため、thisモニター全体のメソッド呼び出しを保持することを意味しています。

EDIT:

...次に待ってmyLockはなくthisに通知を呼び出します。 thisの同期について完全に忘れてください。 (あなたの現在のコードでthisに)待っている間、あなたはmyLockロックを解除していないので、他のスレッドはnotify()に取得することができないからです。

+0

と協力し、あなたは、この(同期を削除するために私に言っています)...私は混乱しています... – kenny

+0

他の答えは、同期(myLock)を除去するために私に指示...私はまだロックを取得し、私は自分のキューを必要と私は、Java 1.4 – kenny

+0

そのうちの1つを削除してください:)。 1つ使用するだけで十分です。それが重要なポイントです。また、デッドロックを取り除くためには、あなたのケースでは必然的に必須です。 –

0

whileifを交換してください。コレクションが本当に空でない/完全でない場合は、チェックを二重にすることを傷つけることはありません。

本当に2つのロックは必要ありません。単一のロックはほとんど同様に機能し、はるかに簡単になるはずです。

public synchronized T get() 
{ 
    while(isEmpty()) 
     wait(0); 

    notifyAll(); 

    return super.get(); 

} 

public synchronized put(T t) 
{ 

    while(isFull()) 
     wait(0); 

    super.put(t); 

    notifyAll(); 

} 

何か変更すると、すべてのスレッドが起動します。しかし、彼らが彼らの仕事をすることができない場合、彼らはの次のnotifyのためになります。

+0

なぜシングルロックで十分ですか?スレッドが完全なキューにデータを追加しようとすると、ループで "if(!isFull())"が絶えずヒットします。 – kenny

+0

なぜnotifyAll()ですか?私は1つのスレッドだけを起動する必要があります – kenny

+0

@kennyそれは必要ではないかもしれませんが、一般的にはいくつかのスレッドが待機している可能性があります。 –

3

は、なぜあなたは3​​文を持っているのですか? wait(0)だけでこれだけ1つを保つ方法及びsynchronized(myLock)から​​をダンプ、thisのロックを解除します。

一部のオブジェクト(この場合はthisを呼び出しています)でwaitを呼び出すと、そのオブジェクトのロックが自動的に解放され、他のスレッドが続行できるようになります。しかし、あなたはに既に電話しているので、myLockで待つことは決してありません。その部分は冗長であり、デッドロックを引き起こします。

このシナリオを検討してください:追加しようとしているスレッドはmyLockのロックを受け取りますが、キューがいっぱいになって待機します。この待ち時間はmyLockのロックを解除しません。他のスレッドはデータを取得したいが、最初のスレッドがmyLockのロックを解除しなかったので、ブロック​​を入力することはできません。

結論:synchronized(myLock)ブロックを削除してください。

+0

通知について同期された(これ)については、私はまだそれが必要ですか? – kenny

+0

@kenny、そうでない場合は、IllegalMonitorStateExceptionがスローされます。待機して通知する呼び出しは、同じオブジェクトの同期ブロック内になければなりません。 – Tudor

+0

今フローは正常に終了するまで(より多くのデータを)終了する必要があります。私のロジックでは、単にキューにnullを追加しますが、最後にはどのようにスタックされているのでしょうか。 – kenny

0

既に述べたように、コードにはあまりにも多くの注釈があります。​​また、waitの条件はifの条件でチェックされますが、spurious wakeupsを回避するにはwhileのループでチェックするのが理想的です。以下は、これらを修正するコードの概要です。

// _isEmpty and _getData are private unsynchronized methods 
public MyData get() throws InterruptedException { 
    // wait and notify should be called from a block 
    // synchronized on the same lock object (here myLock)  
    synchronized (myLock) { 
    // the condition should be tested in a while loop 
    // to avoid issues with spurious wakeups 
    while (_isEmpty()) { 
     // releases the lock and wait for a notify to be called 
     myLock.wait(); 
    } 
    // when control reaches here, we know for sure that 
    // the queue is not empty 
    MyData data = _getData(); 
    // try to wake up all waiting threads - maybe some thread 
    // is waiting for the queue not to be full 
    myLock.notifyAll(); 
    } 
} 

// _isFull and _putData are private unsynchronized methods 
public void put(MyData obj) throws InterruptedException { 
    synchronized (myLock) { 
    while (_isFull()) { 
     myLock.wait(); 
    } 
    _putData(obj); 
    myLock.notifyAll(); 
    } 
} 
関連する問題