BlockingQueue: how can multiple producers stop a single consumer? - java

I wrote a producer/consumer based program using Java's BlockingQueue. I'm trying to find a way to stop the consumer if all producers are done. There are multiple producers, but only one consumer.
I found several solutions for the "one producer, many consumers" scenario, e.g. using a "done paket / poison pill" (see this discussion), but my scenario is just the opposite.
Are there any best practice solutions?

The best-practice system is to use a count-down latch. Whether this works for you is more interesting.....
Perhaps each producer should register and deregister with the consumer, and when all producers are deregistered (and the queue is empty) then the consumer can terminate too.

Presumably your producers are working in different threads in the same VM, and that they exit when done. I would make another thread that calls join() on all the producers in a loop, and when it exist that loop (because all the producer threads have ended) it then notifies the consumer that it's time to exit. This has to run in another thread because the join() calls will block. Incidentally, rolfl's suggestion of using a count down latch would have the problem, if I understand it correctly.
Alternately, if the producers are Callables, then the consumer can call isDone() and isCanceled() on their Futures in the loop, which won't bock, so it can be used right in the consumer thread.

You could use something like the following, i use registerProducer() and unregisterProducer() for keeping track of the producers. Another possible solution could make use of WeakReferences.
It's worth to mention that this solution will not consume the events that have already been queued when the consumer is shut down, so some events may be lost when shutting down.
You would have to drain the queue if the consumer gets interrupt and then process them.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class TestConsumerShutdown {
private static interface SomeEvent {
String getName();
}
private static class Consumer implements Runnable {
private final BlockingQueue<SomeEvent> queue = new ArrayBlockingQueue<>(10);
private final ExecutorService consumerExecutor = Executors.newSingleThreadExecutor();
private final AtomicBoolean isRunning = new AtomicBoolean();
private final AtomicInteger numberProducers = new AtomicInteger(0);
public void startConsumer() {
consumerExecutor.execute(this);
}
public void stopConsumer() {
consumerExecutor.shutdownNow();
try {
consumerExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
public void registerProducer() {
numberProducers.incrementAndGet();
}
public void unregisterProducer() {
if (numberProducers.decrementAndGet() < 1) {
stopConsumer();
}
}
public void produceEvent(SomeEvent event) throws InterruptedException {
queue.put(event);
}
#Override
public void run() {
if (isRunning.compareAndSet(false, true)) {
try {
while (!Thread.currentThread().isInterrupted()) {
SomeEvent event = queue.take();
System.out.println(event.getName());
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
System.out.println("Consumer stopped.");
isRunning.set(false);
}
}
}
}
public static void main(String[] args) {
final Consumer consumer = new Consumer();
consumer.startConsumer();
final Runnable producerRunnable = new Runnable() {
#Override
public void run() {
final String name = Thread.currentThread().getName();
consumer.registerProducer();
try {
for (int i = 0; i < 10; i++) {
consumer.produceEvent(new SomeEvent() {
#Override
public String getName() {
return name;
}
});
}
System.out.println("Produver " + name + " stopped.");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
consumer.unregisterProducer();
}
}
};
List<Thread> producers = new ArrayList<>();
producers.add(new Thread(producerRunnable, "producer-1"));
producers.add(new Thread(producerRunnable, "producer-2"));
producers.add(new Thread(producerRunnable, "producer-3"));
for (Thread t : producers) {
t.start();
}
}
}

Related

How to achieve semaphore concept in Java Multithreading? Producer Consumer

I've two threads Producer and Consumer. In objective-c language I've used semaphores to block and release thread Consumer.
Note: This is related to Producer-Consumer Problem But not fully. Here Producer will not wait for consumer to consume. But consumer will wait till Producer produces. Here Consumer is not continuously reading. He's reading Only when Producer tells him to read. And reads only some data. And here its not about shared memory kinda.
Thread Consumer{
while(true) {
//Consumer is waiting
dispatch_semaphore_wait(semaphoreVariable, DISPATCH_TIME_FOREVER);
//Copies the data and then goes to wait.
}
}
Thread Producer{
while(true){
//write to buffer
//Continuously writes to buffer. No Waiting.
//After writing Some Blocks asks consumer to consume
dispatch_semaphore_signal(semaPhoreBlock);
}
}
Like this the semaphore is used to continuously block and release Consumer Thread.
How to achieve this kind of mechanism in JAVA? Any kind of help is greatly appreciated.
I would solve this coordination problem with a "barrier".
The consumer won't read continuously. It only reads a batch of work when the producer notifies him to do so (by reseting the barrier).
I added some waiting for the producer too (so the queue won't overflow if the consumer is too slow), but the producer will only wait if after producing a batch of work, there is no consumer ready to consume it.
see below:
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
public class BarrierExample {
public static final int BATCH_SIZE = 10;
public static void main(String[] args) throws InterruptedException {
BarrierExample barrierExample = new BarrierExample();
barrierExample.doTheWork();
}
private void doTheWork() throws InterruptedException {
Queue<String> queue = new ConcurrentLinkedQueue();
CyclicBarrier barrier = new CyclicBarrier(2);
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(new Producer(BATCH_SIZE, queue, barrier));
executorService.submit(new Consumer(BATCH_SIZE, queue, barrier));
Thread.sleep(4000);
System.out.println("main program: trying to shutdown executor service");
executorService.shutdownNow();
executorService.awaitTermination(5, TimeUnit.SECONDS);
}
}
class Producer implements Callable<Void> {
private final int batchSize;
private Queue queue;
private CyclicBarrier barrier;
private Random random = new Random();
public Producer(int batchSize, Queue queue, CyclicBarrier barrier) {
this.batchSize = batchSize;
this.queue = queue;
this.barrier = barrier;
}
#Override
public Void call() {
while (true) {
IntStream.range(1, batchSize).forEach(i -> queue.add(String.valueOf(random.ints(1, 10).findFirst().getAsInt())));
System.out.println("producer: batch size was added to queue.");
while (barrier.getNumberWaiting() < 1) {
try {
System.out.println("producer: nobody is waiting on barrier. going to sleep now");
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
if (Thread.currentThread().isInterrupted()) {
break;
}
}
System.out.println("producer: consumer was waiting on barrier. reseting the barrier now");
barrier.reset();
if (Thread.currentThread().isInterrupted()) {
System.out.println("producer is ending now!");
break;
}
}
return null;
}
}
class Consumer implements Callable<Void> {
private final int batchSize;
private Queue queue;
private CyclicBarrier barrier;
public Consumer(int batchSize, Queue queue, CyclicBarrier barrier) {
this.batchSize = batchSize;
this.queue = queue;
this.barrier = barrier;
}
#Override
public Void call() {
while (true) {
boolean barrierIsBroken = false;
try {
System.out.println("consumer: waiting on barrier");
barrier.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (BrokenBarrierException e) {
System.out.println("consumer: barrier is broken!!");
barrierIsBroken = true;
}
if (barrierIsBroken) {
System.out.println("consumer: consuming batch");
IntStream.range(1, batchSize).forEach(i -> System.out.println(queue.remove()));
System.out.println("consumer: queue size:" + queue.size());
}
try {
System.out.println("consumer: going to sleep");
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
if (Thread.currentThread().isInterrupted()) {
System.out.println("consumer is ending now!");
break;
}
}
return null;
}
}
The Java solution is: don't go for "low level" concepts such a using/implemeenting semaphores.
Instead, use one of the many abstractions that the Java platform is offering, for example the LinkedBlockingQueue.
It is pretty simple: when you got two threads, one thread pushes content into the queue; and the the other reader thread uses the take() method in order to fetch content.
Where: take() blocks! Therefore you don't need to worry at all about sending signals "manually". One thread writes, the reader sits and waits until content becomes available. Meaning: you do not need to tell the reader explicitly "start reading" - that happens implicitly, under the covers.
In that sense: the real answer is to study the offerings that Java has to make, instead of trying to build abstractions yourself. A good starting point are the Oracle tutorials on concurrency. Don't assume that your solution from language A must "work" the same way in another language. In Java, the writer does not need to signal the reader when using a BlockingQueue. So don't make your life more complicated by enforcing a concept that comes from another language!

java thread sync between multiple objects

I have a multi-thread multi-object system in which I have a manager and multiple workers. I need to synchronize the workers with the manager, like this:
manager does sth, gives the order to the workers, and then let the workers run in parallel, independent of each other. When they finished this round, they must wait for the manager to give them the new task or order. The manager issues the new order only if all the workers have finished their previous job.
I need to implement it using threads to avoid busy-waiting. However the synchronization is confusing.
Any idea?
EDIT: i missed a important part that says new tasks should arrive only when all have finished. Therefore using LinkedBlockingQueue is not the best solution. I recommend using the CyclicBarrier boris-the-spider has recomended.
You can use a LinkedBlockingQueue
Set a fixed capacity.
The manager can put tasks, and the workers can use function take to wait.
As #boristhespider suggested, I used CyclicBarrier for both manager and workers.
After each worker finishes its task, it calls barrier.await(). Then for the manager, I check if barrier.getNumberWaiting()==NumWorkers. If it's true, it updates the tasks of each worker and then calls barrier.await().
Maintain 2 Blocking queues
1. for Task
2. for free worker
Let worker notify manager via a callback, which add them to free worker queue
Inside manager thread you can check for workers available.
quick implementation
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
public class ManagerWorker {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
BlockingQueue<String> taskQueue = new LinkedBlockingQueue<>();
Manager m = new Manager(5, taskQueue);
service.submit(m);
for (int i = 0; i < 5; i++) {
service.submit(new Worker(m, taskQueue));
}
}
}
class Manager implements Runnable {
int workerCount;
BlockingQueue<Worker> workerqueue = new LinkedBlockingQueue<>();
BlockingQueue<String> taskQueue;
public Manager(int workerCount, BlockingQueue<String> taskQueue) {
this.workerCount = workerCount;
this.taskQueue = taskQueue;
}
public void callBackForFreeNotification(Worker worker) {
workerqueue.add(worker);
}
#Override
public void run() {
while (true) {
try {
int i = 0;
while (i < workerCount) {
workerqueue.take();
i++;
}
System.out.println("Manager Worker available");
// add task to task queue here
for (int j = 0; j < workerCount; j++) {
taskQueue.add("task");
}
System.out.println("Manager task added");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Worker implements Runnable {
private Manager manager;
private BlockingQueue<String> taskQueue;
public Worker(Manager manager, BlockingQueue<String> taskqueue) {
this.manager = manager;
this.taskQueue = taskqueue;
}
#Override
public void run() {
while(true){
try {
System.out.println("Worker - i have no work");
manager.callBackForFreeNotification(this);
taskQueue.take();
System.out.println("Worker working");
Thread.sleep(2000);
System.out.println("Worker Done with work");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

Accessing result of another Thread that's running a loop

Thread A is a loop that performs calculations.
Thread B needs to read result produced by each iteration of loop enclosed in Thread A.
What would be the best approach to achieve this without blocking anything?
You need the Producer-Consumer pattern here. In Java, you can use BlockingQueues to implement it. Here's an example with an ArrayBlockingQueue that is used to deliver Double calculation results from a producer to a consumer:
Producer.java
class Producer implements Runnable {
private final BlockingQueue<Double> queue;
public Producer(BlockingQueue<Double> q) {
queue = q;
}
public void run() {
try {
while (true) {
Double result = calculateResult();
// This call will make the result available to the consumer:
queue.put(result);
}
} catch (InterruptedException ex) {
// Handle thread interruption here
}
}
}
Consumer.java
class Consumer implements Runnable {
private final BlockingQueue<Double> queue;
public Consumer(BlockingQueue<Double> q) {
queue = q;
}
public void run() {
try {
while (true) {
// This call Will wait until the next result is available:
Double result = queue.take();
// Process the result...
}
} catch (InterruptedException ex) {
// Handle thread interruption here
}
}
}
Program.java
class Program {
public static void main() {
BlockingQueue<Double> queue = new ArrayBlockingQueue<>();
Producer producer = new Producer(queue);
Consumer consumer = new Consumer(queue);
new Thread(producer).start();
new Thread(consumer).start();
}
}
If you need, you can create several consumers or several producers (or both) that share the same queue. That will allow you to balance the work between more than two threads.
Also have a look at the BlockingQueue's capabilities and on other implementations, there're plenty of them.

ExecutorService doens't work

I have problem using Executorservice
I implemented Consumer-Producer Pattern
Main
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10000);
Thread producer = new Thread(new Producer(queue));
ExecutorService executorService = Executors.newFixedThreadPool(3);
Runnable consumer1 = new Consumer(queue);
Runnable consumer2 = new Consumer(queue);
Runnable consumer3 = new Consumer(queue);
producer.start();
executorService.submit(consumer1);
executorService.submit(consumer2);
executorService.submit(consumer3);
executorService.shutdown();
}
}
Producer
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable{
public BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10000);
public Producer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
public synchronized void run() {
for (int i=0; i<100; ++i) {
try {
//System.out.println("i = " + i);
queue.put(i);
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
}
Consumer
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Consumer implements Runnable {
public BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10000);
public Consumer(BlockingQueue<Integer> queue) {
this.queue = queue;
}
public void run() {
while (true) {
try {
//queue.take(); // case 1
System.out.println(Thread.currentThread().getName() + " Consumer : " + queue.take()); // case 2
} catch (InterruptedException e) {
System.out.println(e);
}
if (queue.isEmpty()) {
break;
}
}
}
}
I wonder why (Consumer.java) case 1 is not working,
but case 2 is fine
It print noting and never stopping (This comment isn't good. Ignore it ㅠㅠ)
I just wonder, Why case 1 is not Stop.
Is there something in System.out.println or BlockingQueue?
(Poducer.java also. If i added print i in Producer.java then Throws InterruptedException)
May be I don't know java and thread well.
Please help me ;(
(My English isn't good, Sorry)
The fundamental problem here is that if the queue ever becomes empty just before the queue.take(), the consumer thread will block until something gets added to the queue. Since you do all the adding to the queue prior to starting the consumers, it is a matter of luck whether one of the consumers will get into a blocked state.
It appears that case 2 (with the console output) slows things down enough that no thread gets into this state. In case 1 processing is so fast that at least one thread finds itself blocked. When I ran your code I found thread 3 blocked, meaning that probably threads 1 and 2 consumed all entries in the queue before thread 3 even had a chance to get started.
If your usecase involves the queue being filled first by the Producer and then running the Consumer threads, you should use poll() instead of take() which will let you detect the condition of running out of elements.

How to start a remote thread in java?

I have an apllication where there are three folders. I am trying to implement the producer consumer concept using LinkedBlockingQueue.
Folder 1:
Contains a class which has a shared queue
public static BlockingQueue sharedQueue = new LinkedBlockingQueue();
From a method in this class I try to call the Producer thread and the Consumer thread both of which reside in separate files.
Thread updateThread = new Thread(new Producer(sharedQueue));
Thread takeThread = new Thread(new Consumer(sharedQueue));
updateThread.start();
takeThread.start();
Folder 2:Contains the producer thread class as follows:
public class Producer implements Runnable {
private final BlockingQueue Queue;
public Producer(BlockingQueue sharedQueue){
Queue = sharedQueue;
}
public void run()
{
while (Thread.currentThread() != null) {
Random random = new Random();
int pos = random.nextInt(productList.size());
String query = "insert into tab1 values("+pos+")";
Queue.put(query);
}
}
Folder 3: Contains the consumer class as follows:
public class Consumer implements Runnable{
private final BlockingQueue queue;
Collection<String> joblist;
public Consumer (BlockingQueue sharedQueue) {
queue = sharedQueue;
MonitoringForm.txtInforamtion.append("hi"+sharedQueue.size());
joblist = new ArrayList<String>();
}
#Override
public void run() {
while(true){
try {
for(int i = 0; i < queue.size(); i++)
{
joblist.add(queue.take().toString());
MonitoringForm.txtInforamtion.append("What we got "+queue.take().toString());
}
} catch (InterruptedException ex) {
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
}
try {
Thread.sleep(60*1000);
} catch (Exception e) {
}
}
}
}
Can somebody tell me how to make sure that the data added to the shared queue by Producer class can be taken by Consumer class. The consumer consumes the data every minute. Not necessary that data is consumed as soon as it is produced. Calling the Consumer and Producer threads is not working as I have them in separate directories. Do I have to use remote method invocation? Is it possible for threads?
Here's a sample code I wrote which can help you understand the concept:
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* We want a Producer thread to create random values, and the Consumer thread to
* consume it. One caveat is that if the Producer has already created a random
* value, which the Consumer thread hasn't consumed yet, the Producer thread
* blocks or waits. On the flip side, the Consumer thread waits for the Producer
* thread to produce some value if the Producer thread hasn't already.
*
* Write a program to simulate such a situation.
*/
public class ProducerConsumerCommunication
{
private volatile boolean running = true;
private ArrayBlockingQueue<Integer> buffer = new ArrayBlockingQueue<>(1);
private Random random = new Random(System.currentTimeMillis());
private class ProducerTask implements Runnable
{
public void run()
{
while (running)
{
try
{
Thread.sleep(random.nextInt(2000));
Integer value = random.nextInt();
buffer.put(value); // Blocks if buffer is full.
System.out.println("Value Put: " + value);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
private class ConsumerTask implements Runnable
{
public void run()
{
while (running)
{
try
{
Thread.sleep(random.nextInt(2000));
Integer value = buffer.take(); // Blocks if buffer is empty.
System.out.println("Value Taken: " + value);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
public ProducerConsumerCommunication()
{
ExecutorService service = Executors.newCachedThreadPool();
service.execute(new ProducerTask());
service.execute(new ConsumerTask());
service.shutdown();
}
public static void main(String[] args)
{
new ProducerConsumerCommunication();
}
}
In the traditional Consumer/Producer concept the Consumer waits on a resource. And whenever the Producer pushes anything on the Queue it notifies the Consumer via notify() / notifyAll()
Producer :
queue.put(query) ;
obj.notifyAll();
Consumer :
while(true)
{
try {
obj.wait();
}catch (InterruptedException e) {
}
// get data from Queue
data = queue.take();
}
Refer to the following link for more information : example
To run the Producer and Consumer in the fashion like when the Producer produces something in the queue he should Notify the Consumer, and when the Consumer consumed from the queue he should notify to the Producer to produce something in the queue,
To implement your problem in that way you have to use
wait and Notify method if you have one producer and one consumer.
and if you have multiple consumer then you have to use NotifyAll method as well of Object Class,
And in your Consumer if you get this line printed to your console "What we got" then you are sure that Consumer has consumed something from the queue

Categories