Win a copy of Think Java: How to Think Like a Computer Scientist this week in the Java in General forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Newbie Producer Consumer Problem

 
Tirthankar Mukherjee
Ranch Hand
Posts: 51
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator


Expected output like :

Grain Produced is : 1
Grain Consumed is : 1
Grain Produced is : 2
Grain Consumed is : 2


but getting like this :

Grain Produced is : 1
Grain Produced is : 2
Grain Consumed is : 1
Grain Consumed is : 2

Even Worse :


Grain Produced is : 11
Grain Consumed is : 11
Grain Consumed is : 12 =====>>> ???
Grain Produced is : 12


Final Output received


First of all I cant understand why
Producer 1
Producer 2
Consumer 1
Consumer 2

can be a valid output as read in book.

Secondly where is the problem in my code that makes to consume earlier than producing ??

Please Help, thanks in Advance
 
Andrew Monkhouse
author and jackaroo
Marshal Commander
Pie
Posts: 11878
195
C++ Firefox Browser IntelliJ IDE Java Mac Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Very interesting problem. I suspect the problem is with your System.out.println() statements.

If we look at just the run method of the Producer, we see:

Now the ProduceGrain method is synchronized, so the ConsumeGrain cannot run within that method. But nothing else in the Producer class is synchronized, so the moment you exit the ProduceGrain method the JVM is free to swap to another thread - even before the System.out.println statement is executed.

You could move the System.out.println statement into the ProduceGrain method (and the same for the ConsumeGrain's output), or you could synchronize all the code within the respective run methods.
 
Steve Luke
Bartender
Posts: 4181
21
IntelliJ IDE Java Python
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The problem isn't that your consumer ever executes before the producer. The problem is that your reporting mechanism (the System.out.printlns) are outside your synchronized block. Which means that the production and reporting of the production is not a single atomic unit. It is two separate units. Similarly the consumption and reporting of the consumption is not a single execution unit. Because they are not in the same synchronized block, then the Thread context can switch between the Production statement and the Reporting statement, allowing the Consumer to execute between the two.

These are the four steps you need to happen:
1) Production (grain count is incremented and grain is made available)
2) Production is reported (grain count is printed to System.out)
3) Consumption (grain count consumed and grain is made unavailable)
4) Consumption is reported (grain count consumed is printed to System.out)


With your code this is possible:

1) Production (grain count is incremented and grain is made available)
2) Consumption (grain count consumed and grain is made unavailable)
3) Consumption is reported (grain count consumed is printed to System.out)
4) Production is reported (grain count is printed to System.out)

As is this:

1) Production (grain count is incremented (1) and grain is made available)
2) Production is reported (grain count is printed (1) to System.out)
3) Consumption (grain count consumed (1) and grain is made unavailable)
4) Production (grain count is incremented (2) and grain is made available)
5) Production is reported (grain count is printed (2) to System.out)
6) Consumption is reported (grain count consumed is printed (1) to System.out)
7) Consumption (grain count consumed (2) and grain is made unavailable)
8) Consumption is reported (grain count consumed is printed (2) to System.out)


So how would you fix it?

edit == Dern, too slow.
 
Tirthankar Mukherjee
Ranch Hand
Posts: 51
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Many many thanks to both of you Andrew Monkhouse and Steve Luke . I found my problem.

@Andrew

You could move the System.out.println statement into the ProduceGrain method (and the same for the ConsumeGrain's output), or you could synchronize all the code within the respective run methods.


I synchronized the run method but it did not work out ... but making the outputs atomic by putting them in their respective synchronized code worked really well.


@Steve

I fixed it by putting the output statements to the respective synchronized block. You really explained my problem very clearly, I got some better idea now.

 
Andrew Monkhouse
author and jackaroo
Marshal Commander
Pie
Posts: 11878
195
C++ Firefox Browser IntelliJ IDE Java Mac Oracle
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Tirthankar Mukherjee wrote:Many many thanks to both of you Andrew Monkhouse and Steve Luke . I found my problem.

@Andrew

You could move the System.out.println statement into the ProduceGrain method (and the same for the ConsumeGrain's output), or you could synchronize all the code within the respective run methods.


I synchronized the run method but it did not work out ... but making the outputs atomic by putting them in their respective synchronized code worked really well.

True - synchronizing the run method will not work, however it would be possible to synchronize all the code within the run method. Consider:

Of course this would make the method synchronization on ProduceGrain redundant. This type of synchronization can be worth considering if you have other logic that should be synchronized but does not really belong within a particular method.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic