1

我写了一个代码来查看Java中的生产者消费者关系,如下所示。尽管程序运行良好,但我发现输出不一致。有人可以说明以下不一致的原因。

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.
4

2 回答 2

3

日志记录语句不是同步部分的一部分。因此,完全有可能发生以下事件序列:

  • 生产者生产 P,解除阻塞消费者
  • 消费者消费 P,解除阻塞生产者
  • 生产者记录 P 生产
  • 生产者生产 Q,解锁消费者
  • 生产者记录 Q 生产
  • 消费者记录P消费
  • 消费者消费 Q
  • 消费者记录Q消费

这会产生您观察到的输出。

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

于 2013-11-11T15:02:57.163 回答
1

而不是编写wait() / notify()使用来自 JDK 的标准并发类:BlockingQueue接口非常适合多线程环境中的消费者/生产者。

于 2013-11-11T14:51:02.160 回答