java - Java 中生产者消费者关系程序的输出不一致

标签 java multithreading

我编写了一段代码来查看 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.

最佳答案

日志语句不是同步部分的一部分。所以完全有可能发生这样的事件序列:

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

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

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

关于java - Java 中生产者消费者关系程序的输出不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19909088/

相关文章:

java - @Async和任务:annotation-driven don't work

c# - 允许线程有序进入的WaitHandle.WaitAny

c++ - std::thread 的线程安全数组?

java - 成员方法在整个类上同步

java - 建议 Java Swing 组件库

java - 注入(inject)的另一个 CDI bean 是否需要 @DependsOn?

c# - Backgroundworker ReportProgress事件不会触发

.net - 帮助我了解休眠线程的性能和行为

java - Eclipse STS Gradle 插件依赖关系中断

java - 将面板布局设置为 null 时出现 NullPointerException?