Ankit Bansal
Ankit Bansal

Reputation: 2348

Producer Consumer using wait / notifyAll

Consider the following code

import java.util.ArrayList;
import java.util.List;

public class ProducerConsumerExample {

    public static void main(String s[]) {
        List<Integer> taskQueue = new ArrayList<Integer>();
          int MAX_CAPACITY = 5;
          Thread tProducer = new Thread(new Producer(MAX_CAPACITY, taskQueue), "Producer");
          Thread tConsumer = new Thread(new Consumer(taskQueue), "Consumer");
          tProducer.start();
          tConsumer.start();
    }
}

class Consumer implements Runnable{

    List<Integer> taskQueue;
    
    public Consumer(List<Integer> taskQueue) {
        this.taskQueue = taskQueue;
    }
    
    
    
    @Override
    public void run() {
        while(true) {
            consume();
        }
    }
    
    private void consume() {
        synchronized (taskQueue) {
            while(taskQueue.isEmpty()) {
                try {
                    System.out.println("Empty, waiting for more elements");
                    taskQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            
            int i = taskQueue.remove(0);
            System.out.println("Consumed "+i);
            taskQueue.notifyAll();
        }
        
    }
    
}
class Producer implements Runnable{

    final int MAX_CAPACITY;
    List<Integer> taskQueue;
    int counter;
    
    public Producer(int capacity, List<Integer> taskQueue) {
        this.taskQueue = taskQueue;
        this.MAX_CAPACITY = capacity;
    }
    @Override
    public void run() {
        while(true) {
            produce(counter++);
        }
    }
    
    private void produce(int value) {
        
        synchronized (taskQueue) {
            while(taskQueue.size() == MAX_CAPACITY) {
                try {
                    taskQueue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            taskQueue.add(value);
            System.out.println("Produced "+value);
            taskQueue.notifyAll();
        }
        
    }
}

The output for the above program should be random order b/w producer & consumer. Like

Produced 0 
Consumed 0 
and soon

But I am getting the output(always)

Produced 0
Produced 1
Produced 2
Produced 3
Produced 4
Consumed 0
Consumed 1
Consumed 2
Consumed 3
Consumed 4
Empty, waiting for more elements

What am I missing here?

Also, If I places a sysout in produce function at the beginning(before synchronized, they starts coming random)

Upvotes: 0

Views: 43

Answers (1)

zubergu
zubergu

Reputation: 3706

That's a little too long to just put in a comment.
Just to show you what I meant that you can't make any assumptions about order of execution of threads I ran your code without changes on my machine and here's the output:

Produced 0
Consumed 0
Empty, waiting for more elements
Produced 1
Consumed 1
Empty, waiting for more elements
Produced 2
Consumed 2
Empty, waiting for more elements
Produced 3
Consumed 3
Empty, waiting for more elements
Produced 4
Consumed 4
Empty, waiting for more elements
Produced 5
Consumed 5
Empty, waiting for more elements
Produced 6
Consumed 6
Empty, waiting for more elements
Produced 7
Consumed 7
Empty, waiting for more elements
Produced 8
Consumed 8
Empty, waiting for more elements
Produced 9
Consumed 9
Empty, waiting for more elements
Produced 10
Produced 11
Produced 12
Produced 13
Consumed 10
Consumed 11
Consumed 12
Consumed 13
Empty, waiting for more elements
Produced 14
Consumed 14
Empty, waiting for more elements

Your code is fine but you make false assumptions about what is should do.
You made a statement and I quote: "Because two threads running in parallel, so output should be mix of two threads." - no it should not, it might, but to depend on it is wrong.
How threads are actually executed depends on many things like operating system, time sharing policy and many more. Making any assumptions on order of thread execution leads to situations like yours, you expect some behavior and reality doesn't meet your expectations.

Upvotes: 2

Related Questions