• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Newbie Producer Consumer Problem

 
Ranch Hand
Posts: 51
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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
 
author and jackaroo
Posts: 12200
280
Mac IntelliJ IDE Firefox Browser Oracle C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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.
 
Bartender
Posts: 4179
22
IntelliJ IDE Python Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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
    Number of slices to send:
    Optional 'thank-you' note:
  • 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
Posts: 12200
280
Mac IntelliJ IDE Firefox Browser Oracle C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • 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.
reply
    Bookmark Topic Watch Topic
  • New Topic