Terminating out of Producer Consumer setup using wait and notify - java

Please find below consumer producer code:
// Producer
public boolean busy = false;
while (rst != null && rst.next()) {
while (queue.size() == 10) {
synchronized (queue) {
try {
log.debug("Queue is full, waiting");
queue.wait();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
synchronized (queue) {
queue.add(/* add item to queue */);
busy = true;
queue.notifyAll();
}
}
// Consumer
try {
while (!busy) {
while (queue.isEmpty()) {
synchronized (queue) {
try {
log.debug("Queue is empty, waiting");
queue.wait();
} catch (InterruptedException ex) {
ex.getMessage();
}
}
}
synchronized (queue) {
item = queue.remove();
log.debug("Consumed item" + ++count + " :" + item);
busy = false;
queue.notifyAll();
}
}
In my producer code snippet i have synchronized the queue(linked blocking queue) which i am using to add elements and made the global boolean variable busy to true and notify consumer. Once queue size is 10 producer releases object lock and goes to wait state.
For my consumer once global flag busy is true,consumer consumes elements and turn flag to false.
The elements are produced and consumed appropriately.But my code is not terminating out of the producer consumer loop and final statement to be executed is "Queue is empty,waiting".
Please let me know how to modify my code and termination condition to exit out of loop.

Your code is broken is so many ways that it’s hard to decide, where to start. At first, you consumer is entirely enclosed in a while(!busy){ loop so once busy becomes true, it will exit the loop instead of starting to consume items. But since you are accessing the busy variable outside of any synchronization mechanism, there is no guaranty that this thread will ever see a true value written by another thread. At this point, it “helps” that your consumer not really checks the queue’s state when wait returns but just assumes that there are items (which is not guaranteed, read “spurios wakeups”, etc.) The documentation of Object.wait explains how to wait correctly.
But there are more failures to synchronize correctly. In the producer you are saying
while(queue.size() == 10){
synchronized(queue){
…
in other words, you are accessing the queue by calling size() without proper synchronization.
Another issue is your exception handling:
catch(InterruptedException ex)
{
ex.getMessage();
}
calling getMessage but ignoring the result is like not calling it at all. You should add a real action here. Even a simple print statement is better than that.
Further, splitting the wait part and the produce/consume part into two distinct synchronized blocks may work as long as you have exactly one producer and one consumer but as soon as you have more threads, it’s broken since in between these two synchronized blocks, the state of the queue may change again.
Doing it correctly is not so hard, just simplify your code:
//Producer
public volatile boolean producerDone = false;
while( /* can produce more items */ ) {
Item item=produceItem();
synchronized(queue) {
while(queue.size() == 10) try {
log.debug("Queue is full, waiting");
queue.wait();
} catch(InterruptedException ex) {
ex.printStackTrace();
}
queue.add(item);
queue.notifyAll();
}
}
producerDone=true;
 
//Consumer
while(!producerDone) {
Item item;
synchronized(queue) {
while(queue.isEmpty()) try {
log.debug("Queue is empty, waiting");
queue.wait();
} catch(InterruptedException ex) {
ex.printStackTrace();
}
item = queue.remove();
queue.notifyAll();
}
processItem(item);
}

Related

How to interrupt thread to do work and then sleep after doing work?

I want to have a thread which does some I/O work when it is interrupted by a main thread and then go back to sleep/wait until the interrupt is called back again.
So, I have come up with an implementation which seems to be not working. The code snippet is below.
Note - Here the flag is a public variable which can be accessed via the thread class which is in the main class
// in the main function this is how I am calling it
if(!flag) {
thread.interrupt()
}
//this is how my thread class is implemented
class IOworkthread extends Thread {
#Override
public void run() {
while(true) {
try {
flag = false;
Thread.sleep(1000);
} catch (InterruptedException e) {
flag = true;
try {
// doing my I/O work
} catch (Exception e1) {
// print the exception message
}
}
}
}
}
In the above snippet, the second try-catch block catches the InterruptedException. This means that both of the first and second try-catch block are catching the interrupt. But I had only called interrupt to happen during the first try-catch block.
Can you please help me with this?
EDIT
If you feel that there can be another solution for my objective, I will be happy to know about it :)
If it's important to respond fast to the flag you could try the following:
class IOworkthread extends Thread {//implements Runnable would be better here, but thats another story
#Override
public void run() {
while(true) {
try {
flag = false;
Thread.sleep(1000);
}
catch (InterruptedException e) {
flag = true;
}
//after the catch block the interrupted state of the thread should be reset and there should be no exceptions here
try {
// doing I/O work
}
catch (Exception e1) {
// print the exception message
// here of course other exceptions could appear but if there is no Thread.sleep() used here there should be no InterruptedException in this block
}
}
}
}
This should do different because in the catch block when the InterruptedException is caught, the interrupted flag of the thread is reset (at the end of the catch block).
It does sound like a producer/consumer construct. You seem to kind of have it the wrong way around, the IO should be driving the algorithm. Since you stay very abstract in what your code actually does, I'll need to stick to that.
So let's say your "distributed algorithm" works on data of type T; that means that it can be described as a Consumer<T> (the method name in this interface is accept(T value)). Since it can run concurrently, you want to create several instances of that; this is usually done using an ExecutorService. The Executors class provides a nice set of factory methods for creating one, let's use Executors.newFixedThreadPool(parallelism).
Your "IO" thread runs to create input for the algorithm, meaning it is a Supplier<T>. We can run it in an Executors.newSingleThreadExecutor().
We connect these two using a BlockingQueue<T>; this is a FIFO collection. The IO thread puts elements in, and the algorithm instances take out the next one that becomes available.
This makes the whole setup look something like this:
void run() {
int parallelism = 4; // or whatever
ExecutorService algorithmExecutor = Executors.newFixedThreadPool(parallelism);
ExecutorService ioExecutor = Executors.newSingleThreadExecutor();
// this queue will accept up to 4 elements
// this might need to be changed depending on performance of each
BlockingQueue<T> queue = new ArrayBlockingQueue<T>(parallelism);
ioExecutor.submit(new IoExecutor(queue));
// take element from queue
T nextElement = getNextElement(queue);
while (nextElement != null) {
algorithmExecutor.submit(() -> new AlgorithmInstance().accept(nextElement));
nextElement = getNextElement(queue);
if (nextElement == null) break;
}
// wait until algorithms have finished running and cleanup
algorithmExecutor.awaitTermination(Integer.MAX_VALUE, TimeUnit.YEARS);
algorithmExecutor.shutdown();
ioExecutor.shutdown(); // the io thread should have terminated by now already
}
T getNextElement(BlockingQueue<T> queue) {
int timeOut = 1; // adjust depending on your IO
T result = null;
while (true) {
try {
result = queue.poll(timeOut, TimeUnits.SECONDS);
} catch (TimeoutException e) {} // retry indefinetely, we will get a value eventually
}
return result;
}
Now this doesn't actually answer your question because you wanted to know how the IO thread can be notified when it can continue reading data.
This is achieved by the limit to the BlockingQueue<> which will not accept elements after this has been reached, meaning the IO thread can just keep reading and try to put in elements.
abstract class IoExecutor<T> {
private final BlockingQueue<T> queue;
public IoExecutor(BlockingQueue<T> q) { queue = q; }
public void run() {
while (hasMoreData()) {
T data = readData();
// this will block if the queue is full, so IO will pause
queue.put(data);
}
// put null into queue
queue.put(null);
}
protected boolean hasMoreData();
protected abstract T readData();
}
As a result during runtime you should at all time have 4 threads of the algorithm running, as well as (up to) 4 items in the queue waiting for one of the algorithm threads to finish and pick them up.

notifyAll in java

Is it wrong to use notifyAll() inside the loop in a multiple producer-consumer problem in Java?
Here is the code snippet which I am talking about.
public void run() {
while(producer_counter <= 64) {
synchronized(list) {
threadId1 = "Producer " + Thread.currentThread().getName();
//Buffer size is 8
while(list.size() >= 8) {
System.out.println( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
System.out.println(threadId1+ " found the buffer is full & waiting for a Consumer to consume.");
System.out.println( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
try {
list.wait();
list.notifyAll();
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
}
System.out.println(threadId1+ " produced item " + producer_counter);
//Adding the items produced to the list.
list.add(producer_counter);
producer_counter++;
//Invoking notify
list.notifyAll();
}
}
}
}
notifyAll() is to notify all parties about changes in the state of the synchronized object. The first call, which is after wait(), is redundant because no state change happened. This call does not make the program wrong, but only causes waste of CPU cycles: when the buffer is full, notifyAll() is called and all other threads, waiting for the buffer's availability, go to processor only to call notifyAll() again and then call wait(). As a result, one processor in your machine will be always busy making unnecessary work.
BTW, you should not catch InterruptedException (or any other exception) if you don't know why it happened and what to do about it. If, like here, you cannot write public void run() throws InterruptedException, then write
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
Instead of RuntimeException, better declare your own unchecked exception.
You should not use list.notifyAll() in while loop.After adding the items produced to the list list.add(producer_counter) you can use notify all.
// producer thread waits while list is full
while (list.size() >= 8){
list.wait();
}
// to insert the jobs in the list and plus 1 the counter
list.add(producer_counter);
producer_counter++;
// notifies the consumer threads that now it can start
//consuming
list.notifyAll();

What does it mean to return a value after calling wait()?

In the code below I have a question regarding what happens after I call wait(). In my code, I am returning a value after calling wait(), what does this actually do? I thought that calling wait() suspends the current thread, but what happens to the value i passed to addWorkItem(Integer i) if wait() is called without returning false? You can see in the producer thread that it adds i to a retry buffer if it couldn't be added to the deque. If I don't return false after wait, does the value i just get lost, or is it still there once the thread wakes up?
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
public class ConsumerProducer2 {
private static int QUEUE_SIZE = 10;
private Deque<Integer> queue = new ArrayDeque<Integer>(QUEUE_SIZE);
public synchronized boolean addWorkItem(Integer i) {
while (queue.size() >= QUEUE_SIZE) {
try {
wait();
return false; // WHAT HAPPENS HERE?
} catch (InterruptedException ex) {}
}
queue.addLast(i);
notify();
return true;
}
public synchronized Integer getWork() {
while (queue.size() == 0) {
try {
wait();
return null; // WHAT HAPPENS HERE?
} catch (InterruptedException ex) {
}
}
Integer i = queue.removeFirst();
notify();
return i;
}
public static void main(String[] args) {
new ConsumerProducer2().go();
}
public void go() {
ConsumerThread ct = new ConsumerThread();
ct.start();
ConsumerThread ct2 = new ConsumerThread();
ct2.start();
ProducerThread pt = new ProducerThread();
pt.start();
}
class ConsumerThread extends Thread {
public void run() {
while(true) {
Integer work = getWork();
if (work == null) {
} else {
System.out.println("Thread: " + this.getId() + " received work: " + work);
}
}
}
}
class ProducerThread extends Thread {
private List<Integer> retryList = new ArrayList<Integer>();
public void run() {
while(true) {
Integer currWork;
if (retryList.size() == 0) {
currWork = (int) (Math.random() * 100);
} else {
currWork = retryList.remove(0);
System.out.println("Thread: " + this.getId() + " retrying old work: " + currWork);
}
if (!addWorkItem(currWork)) {
System.out.println("Thread: " + this.getId() + " could not add work (because buffer is probably full): " + currWork);
retryList.add(currWork);
} else {
System.out.println("Thread: " + this.getId() + " added work to queue: " + currWork);
}
}
}
}
}
Having the producer maintain a retry buffer does keep the i value from getting lost, but this still isn't a good way to write the method.
Returning from inside the while loop doesn't make sense. You check the size of the queue, and if it's maxed out you wait around until you get a notification that the size of the queue changed, then inexplicably return false (??). The waiting doesn't really accomplish anything.
The point of waiting in addWorkItem is to delay your thread until the queue has room for the new value. You should wait inside a loop, where when you come out of the wait, your thread reacquires the lock and re-checks the condition (queue size > max) to see if it can add the item yet.
Once the thread has exited from the while loop it is holding the lock, it is sure there's enough room in the queue for the new item (because no other threads can do anything to change the size of the queue while this thread has the lock held), and it can go ahead and add the value to the queue.
You are catching the InterruptedException in an unproductive way, because you catch it, don't bother to restore the interrupt flag, and go back to the top of the while loop. You should be using the interruption to quit waiting and get out of the method. Letting InterruptedException be thrown here would make more sense; the thread running the method should know better how to handle the interruption than this object does.
You shouldn't assume wait returns only when the thread is notified, it can return without a notification. That's one of the reasons to call wait in a loop.
Reworked version:
public synchronized boolean addWorkItem(Integer i) throws InterruptedException {
while (queue.size() >= QUEUE_SIZE) {
wait();
}
queue.addLast(i);
notify();
return true;
}
If you want an excuse to return false from this you could make the method return false if the queue doesn't make room for the new entry within some time frame (having a timeout can be a good thing in a lot of real-life situations):
public synchronized boolean addWorkItem(Integer i) throws InterruptedException {
final long maxWaitTime = 60L * 1000;
long totalWaitTime = 0;
while (queue.size() >= QUEUE_SIZE && totalWaitTime <= maxWaitTime) {
long waitStartTime = System.currentTimeMillis();
wait(maxWaitTime);
totalWaitTime += (System.currentTimeMillis() - waitStartTime);
}
if (queue.size() >= QUEUE_SIZE) {
return false;
}
queue.addLast(i);
notify();
return true;
}
This will still use the retry buffer (which the first version above it won't do at all), but probably not nearly as much as you are now.
Another thing: you have producer and consumer threads concurrently accessing this, and notify is called for both cases. Since notify only wakes up one thread, it's possible for a thread to get a notification that isn't relevant for it (so the notified thread wakes up, checks its condition and finds it still false, then waits some more, while another thread that the notification actually matters to never finds out about it). There are different ways to solve the problem, you can
assign separate locks, one for producers and one for consumers,
reduce the timeout passed into the wait method so you're less dependent on getting notified, or
you can use notifyAll (less performant but a quick fix).
Have a look at this.
Short story: A waiting thread can be woken up by another one calling notify. So in your case addWorkItem will return false in a thread that called wait() just after another thread calls notify().
Also having a look at your logic I think you are trying to block the consumer when the queue is empty and awake it when there is job to be done.
And you want the producer not to deliver new jobs until the queue is empty.
If this is the case, then calling return after waiting will just close your consumer/producer not letting them finish their jobs when they can.

How will notifyAll work in this scenario?

Here is the small snippet of multi-threaded queue I wrote,
synchronized void add(int i) {
if (count == size) {
System.out.println("******full***");
isQueueFull = true;
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("adding number: " + i);
val[end++] = i;
count++;
if (isQueueEmpty) {
isQueueEmpty = false;
this.notifyAll();
}
}
synchronized int remove() {
if (count == 0) {
isQueueEmpty = true;
System.out.println("******empty***");
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int t = val[0];
for (int i = 0; i < end - 1; i++) {
val[i] = val[i + 1];
}
val[end - 1] = -1;
end--;
count--;
if (isQueueFull) {
isQueueFull = false;
this.notifyAll();
}
System.out.println("removing number: " + t);
return t;
}
Lets say I have four threads adding to the queue and one thread removing from the queue. At one point,say array get full and I call wait on all four threads adding to the queue.
Now when an element gets removed, I need to call notifyAll on all of the sleeping threads.(It is giving me an arrayOutofBound exception) My questions is this, what is the flow of threads like in case of notifyAll.
Since add is synchronized method, there can only be one thread execution in it. But because of wait, we have now four threading sleeping inside it. So on notifyAll, will all four threads still be inside the add method(despite it being a synchronized method) and execute? or will it done one by one sequentially, with all of the threads being locked until one thread is completed.
It is very difficult for me to debug it in eclipse. I have a work around for arrayOutOfBoundException by putting a return statement after wait, but I would still like to understand the flow in case of notifyAll?
Waiting is very different from sleeping. The javadoc of wait() explains it:
The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
(emphasis mine)
BTW, it also contains a strong rule that you're not respecting:
As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
So, when notifyAll() is called, the 4 threads compete to get back the monitor. Each one gets it back once the previous one has released it, and continues executing.

Producer / Consumer using wait and notify

I am trying to coordinate a producer and consumer thread problem. The producer puts 10 objects on the queue. That is the producer's run method just includes a simple loop to add 10 objects then it is finished. When the queue is full (queue is size 10) there is a call to wait() - > in the queue's add method. On the consumer side, the consumer starts by peeking at the objects and then it starts removing them. The problem I am having is that in roughly 50% of cases when the program is ran, the output terminates after the producer puts the 10 objects on queue. The other 50% of times the program works fine - that is the consumer takes off all the objects. My prior solution to this problem was to create a new consumer thread within the producer's run method. So once the producer had put ten objects on queue, the new consumer thread was created and I used join() to synchronize operations. However I would like to get the process working with wait and notify. Can someone please advise what I am doing wrong? thanks
#Override
public synchronized boolean add(Process element) {
if(isFull())
{
waitForNotify();
}
else
{
queue.add(element);
}
return true;
}
private void invokeNotify() {
try {
notify();
} catch (Exception e) {
e.printStackTrace();
}
}
private void waitForNotify() {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public synchronized boolean offer(Process element) throws IllegalStateException {
queue.add(element);
this.queue = newHeapSort.heapify(queue, queue.size());
return true;
}
#Override
public synchronized Process peek() {
if(queue.isEmpty())
{
waitForNotify();
}
return(queue.get(0));
}
#Override
public synchronized Process head() {
if(queue.isEmpty())
{
invokeNotify();
}
Process head = queue.get(0);
queue.remove(0);
return head;
}
The producer never notifies the consumer thread. So if the consumer is the first to start, it finds the queue empty, and waits eternally.
I would simply use a BlockingQueue, which does that for you.
If you really want to use wait() and notify(), you'll need to:
use a loop around your wait() calls, and go back to the waiting state if the condition to wake up is not true
decide when the producer should notify (normally, when it puts an item in the queue)
decide when the consumer should notify (normally, when it removes an item from the queue)
decide when the consumer should wait (normally, when the queue is empty)
decide when the producer should wait (normally, when the queue is full)
stop ignoring InterruptedException. Just let them propagate.
I would use notifyAll(), which would also make sure that everything works well if there are several producers or consumers.

Categories

Resources