2011-03-02 5 views
2

Java 동시성에 대한 기억이 상쾌 해졌으며 대중적인 생산자 소비자 문제로 놀고있었습니다. 단일 생산자와 단일 소비자가있는 경우 올바르게 작동하는 아래 코드를 구현했습니다. 그러나 여러 생산자/소비자가있는 경우 제대로 작동하지 않습니다.자바에서 다수의 생산자와 소비자 문제 (BlockingQueue 미포함)

public class ProducerConsumer { 

    static Monitor monitor; 

    public ProducerConsumer(int maxSize) 
    { 
     monitor = new Monitor(maxSize); 
     new Producer().start(); 
     new Producer().start(); 
     new Consumer().start(); 
     new Consumer().start(); 
    } 

    class Producer extends Thread{ 

     @Override 
     public void run() { 
      while(true) 
      { 
       try { 
        monitor.insert(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 

    class Consumer extends Thread{ 

     @Override 
     public void run() { 
      while(true) 
      { 
       try { 
        monitor.remove(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 

    class Monitor { 

      int n; 
      int maxSize; 

     public Monitor(int maxSize) 
     { 
      n=0; 
      this.maxSize = maxSize; 
     } 

     synchronized void insert() throws InterruptedException 
     { 
      if(n==maxSize) 
       wait(); 
      System.out.println("Producer: "+n++); 
      if(n==1) 
       notifyAll(); 
     } 

     synchronized void remove() throws InterruptedException 
     { 
      if(n==0) 
       wait(); 
      System.out.println("Consumer: "+n--); 
      if(n==maxSize-1) 
       notifyAll(); 
     } 
    } 

    public static void main(String[] args) { 
     ProducerConsumer pc = new ProducerConsumer(100); 

    } 
} 

답변

8

wait()은 항상 다음과 같은 방법으로 사용되어야하는 이유는 볼 수 없습니다 :

while(condition not met) 
    wait(); 

그렇지 않으면 어떤 스레드가 깨어 조건이 아직 충족되지 않을 때 계속할 수 있습니다. 당신이 notifyAll()를 호출 할 때 그들 중 일부는 너무 늦게, 조건이 다시 거짓 인 경우가 될 수 있도록

  1. , 당신은 모든 대기 스레드를 깨어 (즉, 제한된 자원이 이미 의해 소모 :이 상황에 대한 두 가지 이유가있다 다른 스레드).
  2. 가짜 웨이크 업 (thread awake up) (즉 notify에 해당하지 않음)이 발생할 수 있습니다.

실제로 스레드를 하나만 깨우려면 notifyAll() 대신 notify()을 사용할 수 있습니다. 첫 번째 문제는 없지만 여전히 가짜 웨이크 업에서 사용자를 보호 할 수는 없으므로 while이 여전히 필요합니다.

+0

초 (패드 + 1) – ant

+0

감사합니다. 그러나 동기화 된 메서드는 스레드가 이미 있으면 모든 스레드가 스레드를 입력 할 수 없게한다고 생각했습니다. 이 개념을 이끌어 낸이 개념에 대해 내가 잘못 이해 한 것일까 요? – 3ashmawy

+1

@ 3ashmawy : 예,하지만 스레드가'wait()'를 호출하면 잠금을 해제합니다. 이후의'notifyAll()'대기 상태의 쓰레드가 대기 상태가되어 잠금을 다시 얻고'wait()'후에 계속된다. 분명히 대기열의 첫 번째 스레드는 상태를 변경하고 마지막 스레드는 다시 충족되지 않는 조건을 찾습니다. – axtavt