2017-07-06 2 views
0

プロデューサ/コンシューマをモデル化したこのシンプルな並行性のOracleの問題で数日間苦労しました。これは私がguardedブロック、wait、およびnotifyAllを使用した初めてのことです。しかし、私はこれらの方法が何をするか知っています。私はどのようなステップが最初に起こるかは分かりません。私は下に行くことができるように問題を追跡するつもりで、あなたが私が正しいかどうか教えてくれます。Javaで保護されたブロックをトレースする

  1. プロデューサ/コンシューマスレッドは、メインスレッドから開始されます。それぞれに同じDropインスタンスが与えられます。
  2. コンシューマスレッドがプロデューサより速い場合、プロデューサは組み込みのロックを取得し、メッセージをループ内でdrop.take()から出力しようとします。しかし、プロデューサーはemptyが真であるため、消費者にメッセージを与えていません。この結果、スレッドが中断され、ロックが解除されます。それは今待っている。
  3. プロデューサスレッドは、ループ内でdrop.put()を呼び出します。 emptyがtrueであり、Consumerのメッセージを準備する必要があるため、ドロップ時の固有のロックを取得してメソッドを続行します。 emptyをfalseに設定してメッセージを格納します。 Consumer Threadを起動するnotifyAll()が呼び出されます。 emptyがfalseになり、ロックが解除されるため、プロデューサも待機しています。
  4. drop.take()が通知され、プロデューサが本質的なロックオンのロックを持っていたため、このメソッドを起動します。 Emptyがtrueに設定され、メッセージが返され、ループ内に印刷されます。新しいメッセージが必要なため、プロデューサースレッドに目を覚ますように通知するようになりました。
  5. プロデューサーが待っていました。 emptyがtrueで、スレッドに通知され(ロックがアクセスされたため)、スレッドは目覚めて別のメッセージを生成することができます。

ドロップクラス

package Store; 
 

 
public class Drop { 
 
    // Message sent from producer 
 
    // to consumer. 
 
    private String message; 
 
    // True if consumer should wait 
 
    // for producer to send message, 
 
    // false if producer should wait for 
 
    // consumer to retrieve message. 
 
    private boolean empty = true; 
 

 
    public synchronized String take() { 
 
     // Wait until message is 
 
     // available. 
 
     while (empty) { 
 
      try { 
 
       wait(); 
 
      } catch (InterruptedException e) {} 
 
     } 
 
     // Toggle status. 
 
     empty = true; 
 
     // Notify producer that 
 
     // status has changed. 
 
     notifyAll(); 
 
     return message; 
 
    } 
 

 
    public synchronized void put(String message) { 
 
     // Wait until message has 
 
     // been retrieved. 
 
     while (!empty) { 
 
      try { 
 
       wait(); 
 
      } catch (InterruptedException e) {} 
 
     } 
 
     // Toggle status. 
 
     empty = false; 
 
     // Store message. 
 
     this.message = message; 
 
     // Notify consumer that status 
 
     // has changed. 
 
     notifyAll(); 
 
    } 
 
}

消費者クラス:

package Store; 
 

 
import java.util.Random; 
 

 

 
public class Consumer implements Runnable { 
 
    private Drop drop; 
 

 
    public Consumer(Drop drop) { 
 
     this.drop = drop; 
 
    } 
 

 
    public void run() { 
 
     Random random = new Random(); 
 
     for (String message = drop.take(); 
 
      ! message.equals("DONE"); 
 
      message = drop.take()) { 
 
      System.out.format("MESSAGE RECEIVED: %s%n", message); 
 
      try { 
 
       Thread.sleep(random.nextInt(5000)); 
 
      } catch (InterruptedException e) {} 
 
     } 
 
    } 
 
}

プロデューサークラス:

package Store; 
 

 

 
import java.util.Random; 
 

 
public class Producer implements Runnable { 
 
    private Drop drop; 
 

 
    public Producer(Drop drop) { 
 
     this.drop = drop; 
 
    } 
 

 
    public void run() { 
 
     String importantInfo[] = { 
 
      "Mares eat oats", 
 
      "Does eat oats", 
 
      "Little lambs eat ivy", 
 
      "A kid will eat ivy too" 
 
     }; 
 
     Random random = new Random(); 
 

 
     for (int i = 0; 
 
      i < importantInfo.length; 
 
      i++) { 
 
      drop.put(importantInfo[i]); 
 
      try { 
 
       Thread.sleep(random.nextInt(5000)); 
 
      } catch (InterruptedException e) {} 
 
     } 
 
     drop.put("DONE"); 
 
    } 
 
}

メインスレッド:

public class ProducerConsumerExample { 
 
    public static void main(String[] args) { 
 
     Drop drop = new Drop(); 
 
     (new Thread(new Producer(drop))).start(); 
 
     (new Thread(new Consumer(drop))).start(); 
 
    } 
 
}

答えて

0

私は完全な答えを持っていないが、私は、観測のカップルを持っています。

ウェイトをラップしている間は、ループすると例外が発生します。 waitはロックが必要ですが、waitはロックを解除します。幸いにも、あなたはその行動を経験すべきではありません。

インスタンス変数がスレッド間で更新されないという問題が発生することがあります。同期してから、待ってください。これは、それらの変数が異なる値を持つ機会を提供します。それらを揮発性とすることは、それを助けるでしょう。

あなたのコードが実際に行っていることを言っていませんでした...

+0

他のメッセージで繰り返される最初のメッセージの手順をたどってきました。私はあなたが待っている方法についての言葉が好きで、ロックを解除しました。 – retchers

関連する問題