Java中生产者消费者关系计划的输出不一致

时间:2013-11-11 14:46:26

标签: java multithreading

我编写了一个代码来查看Java中的Producer Consumer关系,如下所示。 虽然程序工作正常但我看到输出不一致。 有人可以说明以下不一致的原因。

class ProdCons2
{
   public static void main (String [] args)
   {
      Shared s = new Shared ();
      new Producer (s).start ();
      new Consumer (s).start ();
   }
}

class Shared
{
   private char c = '\u0000';
   private boolean writeable = true;

   synchronized void setSharedChar (char c)
   {
      while (!writeable)
         try
         {
            wait ();
         }
         catch (InterruptedException e) {}

      this.c = c;
      writeable = false;
      notify ();
   }

   synchronized char getSharedChar ()
   {
      while (writeable)
         try
         {
            wait ();
         }
         catch (InterruptedException e) { }

      writeable = true;
      notify ();

      return c;
   }
}

class Producer extends Thread
{
   private Shared s;

   Producer (Shared s)
   {
      this.s = s;
   }

   public void run ()
   {
      for (char ch = 'A'; ch <= 'Z'; ch++)
      {
           try
           {
              Thread.sleep ((int) (Math.random () * 1000));
           }
           catch (InterruptedException e) {}

           s.setSharedChar (ch);
           System.out.println (ch + " produced by producer.");
      }
   }
}

class Consumer extends Thread
{
   private Shared s;

   Consumer (Shared s)
   {
      this.s = s;
   }

   public void run ()
   {
      char ch;
      do
      {
         try
         {
            Thread.sleep ((int) (Math.random () * 1000));
         }
         catch (InterruptedException e) {}

         ch = s.getSharedChar ();
         System.out.println (ch + " consumed by consumer.");
      }
      while (ch != 'Z');
   }
}

它给了我如下输出:

 A produced by producer.
    A consumed by consumer.
    B produced by producer.
    B consumed by consumer.
    C produced by producer.
    C consumed by consumer.
    D produced by producer.
    D consumed by consumer.
    E produced by producer.
    F produced by producer.
    E consumed by consumer.
    F consumed by consumer.
    G produced by producer.
    G consumed by consumer.
    H produced by producer.
    I produced by producer.
    H consumed by consumer.
    I consumed by consumer.
    J produced by producer.
    J consumed by consumer.
    K produced by producer.
    L produced by producer.
    K consumed by consumer.
    L consumed by consumer.
    M produced by producer.
    M consumed by consumer.
    N produced by producer.
    N consumed by consumer.
    O produced by producer.
    O consumed by consumer.
    P produced by producer.
    Q produced by producer.
    P consumed by consumer.
    Q consumed by consumer.
    R produced by producer.
    R consumed by consumer.
    S produced by producer.
    S consumed by consumer.
    T produced by producer.
    T consumed by consumer.
    U produced by producer.
    U consumed by consumer.
    V produced by producer.
    V consumed by consumer.
    W consumed by consumer.
    W produced by producer.
    X produced by producer.
    X consumed by consumer.
    Y consumed by consumer.
    Y produced by producer.
    Z produced by producer.
    Z consumed by consumer.

观察P和Q处的输出:

P produced by producer.
Q produced by producer.
P consumed by consumer.
Q consumed by consumer.

控制台不打印的原因是什么:

P produced by producer.
P consumed by consumer.
Q produced by producer.
Q consumed by consumer.

2 个答案:

答案 0 :(得分:3)

日志记录语句不是同步部分的一部分。因此,完成这一系列事件是完全可能的:

  • 生产者生产P,解锁消费者
  • 消费者消费P,取消阻止生产者
  • 生产者记录P生产
  • 制作人生成Q,取消阻止消费者
  • 生产者记录Q production
  • 消费者记录P消费
  • 消费者消费Q
  • 消费者记录Q消费

产生你观察到的输出。

如果您希望在生产之后始终记录消耗,那么日志记录语句应该在代码的同步部分内。

答案 1 :(得分:1)

而不是编写wait() / notify()使用JDK中的标准并发类:BlockingQueue接口非常适合多线程环境中的Consumer / Producer。