2017-06-07 13 views
1

私は、1つのスレッドがメッセージをVectorに入れ、もう1つがメッセージをVectorから取り除く、Producer/Consumerの問題の解決策を作成しようとしています。なぜコンシューマスレッドはVectorからメッセージを削除できないのですか?

import java.util.Vector; 
public class Producer implements Runnable { 
    static final int MAXQUEUE = 5; 
    private Vector<String> messages; 

    public Producer(Vector<String> messages) { 
     super(); 
     this.messages = messages; 
    } 

    @Override 
    public void run() { 
     try { 
      while (true) 
       putMessage(); 
     } catch (InterruptedException e) { 
     } 
    } 

    private synchronized void putMessage() throws InterruptedException { 
     while (messages.size() == MAXQUEUE) { 
      wait(); 
     } 
     messages.addElement(new java.util.Date().toString()); 
     System.out.println("put message"); 
     notifyAll(); 
    } 

    public static void main(String args[]) {  
     Vector<String> messages = new Vector<String>(); 
     new Thread(new Producer(messages)).start(); 
     new Thread(new Consumer(messages)).start(); 
    } 
} 

class Consumer implements Runnable{ 
    public Consumer(Vector<String> messages) { 
     super(); 
     this.messages = messages; 
    } 
    private Vector<String> messages; 

    public synchronized String getMessage() throws InterruptedException { 
     notifyAll(); 
     while (messages.size() == 0) { 
      wait();//By executing wait() from a synchronized block, a thread gives up its hold on the lock and goes to sleep. 
     } 
     String message = (String) messages.firstElement(); 
     messages.removeElement(message); 
     return message; 
    } 

    @Override 
    public void run() { 
     try { 
      while (true) { 
       String message = getMessage(); 
       System.out.println("Got message: " + message); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

プログラムを実行しているときはいつでも、メッセージを5回印刷しています。私はnotifyAll()の後でさえ、消費者にロックを与えていないことを理解していません。

+0

これは問題ではないかもしれませんが、mainメソッドを別のドライバクラスに入れてみてください。 –

+0

あなたはそれがいっぱいになるまでできるだけ早く入れていますが、プロデューサの呼び出しがwait()になるまで消費者がロックを取得できなければ私は驚くことはありません。 –

+2

BTW BlockingQueueを使用すると、プロデューサがコンシューマをロックアウトしないので、はるかに簡単で効率的になります。つまり、追加と削除を同時に行うことができます。 –

答えて

2

あなたのコードが動作していない書くことができます。

それぞれは、共有モニタではなく、それぞれ独自のモニタで通知および待機します。共有モニターを使用するようにコードを変更します(例:同期を含むmessages

private void putMessage() throws InterruptedException { 
    synchronized (messages) { // <====== 
     while (messages.size() == MAXQUEUE) { 
      messages.wait(); // <====== 
     } 
     messages.addElement(new java.util.Date().toString()); 
     System.out.println("put message"); 
     messages.notifyAll(); // <====== 
    } 
} 

public String getMessage() throws InterruptedException { 
    synchronized (messages) { // <====== 
     while (messages.size() == 0) { 
      messages.wait(); // <====== 
     } 
     String message = (String) messages.firstElement(); 
     messages.removeElement(message); 
     messages.notifyAll(); // <====== 
     return message; 
    } 
} 

メソッドが同期されていないことに注意してください。

+0

Synchronizedブロックの代わりにSynchronizedメソッドを使用することはできませんか? – Vicky

+0

@Vickyいいえ、synchronizedメソッドは 'synchronized(this){'と同じです。つまり、2つのクラスが2つの異なるオブジェクトで同期していることを意味します。 – Andreas

+0

ありがとうAndreas。今問題が出ています。この場合、「this」はThreadオブジェクトです。 – Vicky

0

コンソールへのロギングは非常に遅いので、ロックを保持せずにこれを行うと、消費者にチャンスが与えられます。

@Override 
public void run() { 
    try { 
     while (true) { 
      // slows the producer a little to give the consumer a chance to get the lock. 
      System.out.println("put message"); 
      putMessage(); 
     } 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
} 

private void putMessage() throws InterruptedException { 
    synchronized (messages) { 
     while (messages.size() == MAXQUEUE) { 
      messages.wait(); 
     } 
     messages.addElement(new java.util.Date().toString()); 
     messages.notifyAll(); 
    } 
} 

はところで、消費者に、あなたの2つのスレッドが同じモニターで待機/通知されていないので、この

public String getMessage() throws InterruptedException { 
    synchronized (messages) { 
     while (messages.isEmpty()) { 
      messages.wait();//By executing wait() from a synchronized block, a thread gives up its hold on the lock and goes to sleep. 
     } 
     messages.notifyAll(); 
     return messages.remove(0); 
    } 
} 
+0

それでも動作しません。 Andreasのソリューションを試してみよう – Vicky

+0

@Vicky彼は正しいです、あなたはRunnableではなく共有オブジェクトであるコレクションを同期させる必要があります。 –

関連する問題