Actually there are quite a few similar threads here on the same subject. You could search for them. Although not exactly similar to your case, those discussions may give you valuable insights.
Coming to your problem, one of the thing that is incorrect with your code is the following part. If you look well, you'd realize that you're not producing 49 though it gets printed. You might want to do some rearrangement of instructions there so you display exactly what the producer produces.
Also for how long to produce and when to stop producing is an aspect specific to a particular producer. You may want to remove that logic altogether from the Queue class and have it in your Producer class, although differently ( explained below ).
To address the case of how to exit, you could use the concept of a Poison Pill. It's not a valid value to be produced/consumed but it is something that you could have the Producer and Consumers
test for. Like you could have the producer and consumer constructor accept an Integer Object like this.
In the producer code, you could produce this value as the last value. The consumer code could check if the value is equal to ( use == here ) the killSignal and then it can stop. Since you have multiple consumers, you may want to add the value back so other consumers can again consume this value.
Few days back I was also working on a similar problem and Steve had suggested me a very elegant enum approach ( also this approach is his suggestion ). I liked it a lot. If you like you can search for it in the forum Threads and Synchronization.
Hope it helps.
Chan.
Edit : Since you have multiple consumers, the enum approach might not be handy here, though I admit I haven't thought deeply about it ( I will, later :-) ).