1

I am trying, and failing, to implement a Producer Consumer pattern in java, subject to the following constraints:

  • The Producer produces into (and the Consumer consumes from) a queue with finite size
  • There is a user interface with buttons toggling the Producer and Consumer, separately
  • The Producer should produce only when queue is not full and the producer button is toggled active,
  • The Consumer should consume only when the queue is not empty and the consumer button is toggled active.
  • Both production and consumption should be possible at the same time. (It so happens that production will be at least as possible as consumption, and sometimes faster.)

My thought was to implement the buffer as a LinkedBlockingQueue of finite size, to handle the conditions relating to the queue empty/full states-- it should block when trying to put to a full queue or take from an empty one. Then, use a boolean state on the producer and the consumer, triggered off the buttons. Finally use a while/wait/loop in the producer and consumer, and a notify in the code for the buttons.

Something like the following, for the producer side:

  while (true) { 
    if (!producing) { wait(); }
    //  generate a bunch of data and and finally        
    //  Save this chunk of data
    buffer.addData(data);
  }

And in the code for the producer button, we both toggle the producing state and call a method on the producer that self notifies.

Problem: Once the producer is producing, it polls so hard even the UI (implemented in Swing) loses responsiveness. I can fix that by wadding a wait(1); statement, but for various non-negotiable reasons that's just not acceptable. Some delay is inevitable, but a 1 ms delay each time through the loop just won't work.

I'm also not convinced I have the right understanding of the LinkedBlockingQueue, either, since if I let the the queue fill up, I still lose UI responsiveness. I am clearly misunderstanding how theaded operations in Java work, as I've tried multiple approaches and this is the closest I've got; previous approaches trying to handle the full/empty conditions "manually" without the LinkedBlockingQueue were miserable failures.

Any advice would be appreciated. Surely what I'm trying to do (lock on two conditions without excessive polling) isn't impossible, is it?

Novak
  • 4,687
  • 2
  • 26
  • 64

2 Answers2

4

This discussion includes the program TwoTimer, in which a javax.swing.Timer increments an int at 100 Hz, while a java.util.TimerTask samples the value at 1 Hz. A variation stores the samples in a LinkedBlockingQueue, forming a recent history queue. It's not directly related to your task, but it illustrates an essential requirement for a responsive GUI: never block the event dispatch thread. The example uses invokeLater() to perform the next collection.

Also consider nextGaussian() for simulated latency, as illustrated here.

As an aside, you might enjoy this example that animates a queue of geometric shapes.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
2

What you have described should work fine. Posting your actual code (abstract out the actual production and actual consumption) would help. You said

it polls so hard even the UI loses responsiveness

that seems to mean you are misusing the LinkedBlockingQueue. You should not be polling the queue repeatedly. You should get an item off the queue, process it then check the production flag, and produce and enqueue the item, or wait() on the monitor upon which the UI calls notifyAll().

Jim
  • 1,161
  • 9
  • 21
  • But production and consumption **may** be simultaneously enabled, but they're not **required** to be. So production only might be enabled without consumption. I will update with additional code tomorrow. – Novak Mar 21 '12 at 06:16