2017-02-15 12 views
0

Javaでモニタを使用して単一のコンシューマ/プロデューサの問題を解決しようとしています。コードは次のとおりです。私はこのコードを実行すると、それはついに詰まるでしょう。最も一般的なケースは、コンシューマがwait()を呼び出し、プロデューサはコンシューマを生成し続けますが、コンシューマに通知することはできません(notify()を呼び出します)。私はなぜそれが起こっているのか分からない。 Javaコード:私のJavaプログラムのモニタがデッドロックになる

import java.util.*; 
class Monitor { 
    int length; 
    int size; 
    int begin, end; 
    int queue[]; 
    private static Random randGenerator; 
    public Monitor() {} 
    public Monitor(int length) { 
     this.length = length; 
     this.size = 0; 
     begin = end = 0; 
     queue = new int[length]; 
     randGenerator = new Random(10); 
    } 
    public synchronized void produce() throws InterruptedException { 
     while(size == length) { 
      System.out.println("Producer waiting"); 
      wait(); 
     } 
     int produced = randGenerator.nextInt(); 
     size++; 
     queue[end] = produced; 
     end = (end + 1) % length; 
     System.out.println("Produce element " + produced + " size "+size); 
     // When size is not 1, no thread is blocked and therefore don't need to notify 
     if(size == 1) { 
      System.out.println("Notify consumer"); 
      notify(); 
     } 
    } 
    public synchronized void consume() throws InterruptedException { 
     while(size == 0) { 
      System.out.println("Consumer waiting, size " + size); 
      wait(); 
     } 
     size--; 
     System.out.println("Consume element " + queue[begin] + " size " + size); 
     begin = (begin + 1) % length; 
     if(size == length - 1) { 
      System.out.println("Notify producer"); 
      notify(); 
     } 
    } 
} 

class Producer implements Runnable { 
    Monitor producer; 
    public Producer(Monitor m) { 
     producer = m; 
    } 
    @Override 
    public void run() { 
     producer = new Monitor(); 
     System.out.println("Producer created"); 
     try { 
      while(true) { 
       producer.produce(); 
      } 
     } 
     catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
class Consumer implements Runnable { 
    Monitor consumer; 
    public Consumer(Monitor m) { 
     consumer = m; 
    } 
    @Override 
    public void run() { 
     System.out.println("Consumer created"); 
     consumer = new Monitor(); 
     try { 
      while(true) { 
       consumer.consume(); 
      } 
     } 
     catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

public class monitorTest { 
    public static void main(String args[]) { 
     Monitor monitor = new Monitor(10); 
     Thread t1 = new Thread(new Producer(monitor)); 
     Thread t2 = new Thread(new Consumer(monitor)); 
     t1.start(); 
     t2.start(); 
    } 
} 
+0

2人の消費者が最初に来て、両方とも 'wait()'と入力したとします。プロデューサが来たら、1つの 'notify()'を発行します。その後直ちに、消費者が目覚める前に、別のプロデューサが来て、アイテムを追加するが通知は一切出さない。今、消費者は1人しか目覚めされません。 – ZhongYu

+0

@ ZhongYuご意見ありがとうございます。主な機能でプロデューサと消費者を1つだけ作成しても、プログラムは正常に実行できません。何故ですか?私はプログラムが単一の生産者/消費者の問題を対象としていると述べました。 –

+0

もう一度 'new Monitor()'を呼び出すべきではありません。main()で作成されたモニタを使用してください。 – ZhongYu

答えて

1

各スレッドの制御はproduce()又はconsume()方法に入ると、大きさと長さは共にゼロであり、他方が通知するために、したがって、両方のスレッドが待っています。これを中断し、あなたのコードはデッドロックから外れるでしょう。

public synchronized void produce() throws InterruptedException { 
    while(size == length) { // size is 0 and length is 0; so wait 
     System.out.println("Producer waiting"); 
     wait(); 
    } 

public synchronized void consume() throws InterruptedException { 
    while(size == 0) { // size is 0 so wait 
     System.out.println("Consumer waiting, size " + size); 
     wait(); 
    } 

あなたがあなたの生産と消費のオブジェクトのrun()メソッド内で呼び出しているデフォルトコンストラクタを持っているので、これが起こっています。

class Producer implements Runnable { 
    Monitor producer; 
    public Producer(Monitor m) { 
     producer = m; 
    } 
    @Override 
    public void run() { 
     producer = new Monitor(); // REMOVE THIS 

class Consumer implements Runnable { 
    Monitor consumer; 
    public Consumer(Monitor m) { 
     consumer = m; 
    } 
    @Override 
    public void run() { 
     System.out.println("Consumer created"); 
     consumer = new Monitor(); // AND REMOVE THIS 

この情報がお役に立てば幸い!

+0

しかし、私はmonitor.lengthを10( 'Monitor monitor = new Monitor(10)')に初期化するので、長さは0ではなく10にするべきです。間違っていますか? –

+0

'while'ステートメントの開始前にサイズと長さを表示しました。私はサイズ= 0と長さ= 0を持っています。 – anacron

+0

更新された答えを参照してください。 – anacron

関連する問題