1

I wrote a code to see Producer Consumer relationship in Java as below. Although the program is working fine I see an inconsistency in the output. Can somebody please specify the reason for the below inconsistency.

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');
   }
}

It gave me the output as below :

 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.

Observe the output at P and Q :

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

What is the reason that the console is not printing :

P produced by producer.
P consumed by consumer.
Q produced by producer.
Q consumed by consumer.
Nishant Lakhara
  • 2,295
  • 4
  • 23
  • 46

2 Answers2

3

The logging statements are not part of the synchronized section. So it's perfectly possible to have this sequence of events:

  • producer produces P, unblocks consumer
  • consumer consumes P, unblocks producer
  • producer logs P production
  • producer produces Q, unblocks consumer
  • producer logs Q production
  • consumer logs P consumption
  • consumer consumes Q
  • consumer logs Q consumption

which produces the output you observe.

If you want the consumption to be always logged right after the production, then the logging statements should be inside the synchronized sections of the code.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
1

Instead of writing wait() / notify() use standard concurency classes from JDK : BlockingQueue interface is perfect for Consumer/Producer in multithreading env.

Areo
  • 928
  • 5
  • 12
  • Although the output is inconsistent, it is not incorrect. I think the System.out.println() is not placed at proper position. When ch = s.getSharedChar() is called, ch receives the value P and immediately s.setSharedChar(ch) and System.out.println() statement below it is called and prints Q produced by producer. And after that P consumed by consumer is printed following the get method of consumer thread. – Nishant Lakhara Nov 11 '13 at 15:06