Search code examples
javadesign-patternsproducer-consumerblockingqueue

Should blocking queue be defined in Producer Class or Consumer class?


I have made 2 classes of Producer and Consumer. Producer class creates threads and pushes the items to the blocking queue and consumer class also creates threads which takses the items from the blocking queue.

Now, I was wondering one thing here. Should I define my blocking queue in Producer or in Consumer class? Or it should be a singleton object which is defined in both producer and consumer?

If I define in only one class, then I can access the blocking queue by calling the method of that class from another class. This kind of encapsulates the blocking queue data structure in that class and we are accessing that data structure only by the use of the methods. But, I find calling through method makes it look like, one class is dependent on another class.

While if I create a singleton blocking queue, then, the blocking queue object is shared between 2 classes. But I think its bad practice to share collections between classes making users to know that how to use collections in each class. I am not sure if its really a bad practice.

Please provide your insights on which way is better? Thanks for your help.


Solution

  • A blocking queue should be instantiated in the producer class, because the producer actually controls this collection. Consumer would tell the Producer to produce. Instead of the finished product, the Producer returns the blocking collection and sets it to complete once the production is finished. This way the consumer can iterate the blocking collection and knows when to break this iteration. According to this flow, I would instantiate the blocking collection in the Producer scope. But it doesn't really matter. Otherwise the Producer would accept a parameter of a in an external scope created collection. It's turns down to be a question of taste and I think it's cleaner to let the Producer return the collection

    I prefer a)

    BlockingQueue result = producer.produce();
    while (!result.isCompleted) {}
    

    over b)

    BlockingQueue result = new BlockingQueue();
    producer.produce(result);
    while (!result.isCompleted) {}
    

    Since Java doesn't now references (only copies of references), using my preferred solution a) would give the producer all the freedom to overwrite the BlockingQueue at any time without causing trouble to the Consumer.

    Singletons are not good practice and should be avoided whenever possible:

    • Singletons will complicate your tests since you can't mock them.
    • Singletons introduce high coupling due to their static nature.
    • And because of their static nature they are expensive in concurrent scenarios (which might not be relevant in your case), since they would require synchronization or thread-safety
    • Singletons are not controllable in terms of their lifetime. Its lifetime is coupled to the lifetime of the application (or the domain)