Search code examples
javamultithreadingproducer-consumer

Producer Consumer problem - can't find the what's wrong


I am a beginner in Java trying producer consumer problem using multi-threading in Java.

Problems observed

  • One thread isn't executing and I can't find why.
  • There ain't any errors but output is not matching.
  • The producer thread is running, still the consumer isn't.

The code

All classes are in one file with imports:

import java.util.LinkedList;
import java.util.*;

For readability I have split them here.

class fun {
    LinkedList<Integer> list = new LinkedList<>();
    int capacity=3;
    
    synchronized void produce()throws InterruptedException {
        int val=0;
        while(true) {
            while(list.size() == capacity) {
                wait();
            }
            System.out.println("Producer Produced : "+val);
            list.add(val);
            val++;
            notify();
        }
    }
    
    synchronized void consume() throws InterruptedException { 
        while(true) {
            while(list.size() == 0) {
                wait();
            }
            int val;
            val = list.removeFirst();
            System.out.println("Consumer consumed-"+ val);
            notify();
        }
    }
}

class a defines one thread:

class a extends Thread {
    public void run() {
        try {
            fun obj=new fun();
            obj.produce();
        } catch(InterruptedException e) {
            System.out.println(e);
        }
    }
}

class b defines the other thread:

class b extends Thread {
    public void run() {
        try {
            fun obj=new fun();
            obj.consume();
        } catch(InterruptedException e) {
            System.out.println(e);
        }
    }
}

class pcp contains the main method:

class pcp {
    public static void main(String[]args) throws InterruptedException {
        a t1=new a();
        b t2=new b();
        t1.start();
        System.out.println(t1.isAlive());
        t2.start();
        System.out.println(t1.isAlive());
        t1.join();
        t2.join();
    }
}

Output

C:\javaprogs>java pcp
true
true
Producer Produced : 0
Producer Produced : 1
Producer Produced : 2

I have been checking what's wrong in my Java code but I cant find any answer.


Solution

  • The problem with your code/approach is that, you are using two different objects of class fun which ideally should have been a common shared resource among multiple threads.

    Inside class b you are instantiating new object of fun as shown below

    try{    
        fun obj=new fun();
        obj.consume();
    }
    

    As instance of class b was never shared, below condition would always met

    while(list.size() == 0) {
          wait();
    }
    

    and there would no other thread notifying to this waiting thread, because your producer thread is dealing with monitor of a; not b. This is causing your producer thread to continue only printing aforesaid stuff.

    Now, to get rid of this issue, you can follow below steps

    1. Consider declaring fun as a member of class a & b both
    2. Provide a constructor in both a & b accepting fun type and initialise it with member variable
    3. Inside run() method, try invoking produce() & consume() on fun member variable
    4. Final step is, inside your main, create an object of fun and use it to create instances of a & b

    Complete code with some modifications to your code is shown below.

    import java.util.*;
    
    public class pcp {
        public static void main(String[] args) throws InterruptedException {
            fun f = new fun();
            a t1=new a(f);
            b t2=new b(f);
            t1.start();
            System.out.println(t1.isAlive());
            t2.start();
            System.out.println(t1.isAlive());
            t1.join();
            t2.join();
        }
    }
    
    class fun {
        LinkedList<Integer> list = new LinkedList<>();
        int capacity = 3;
    
        synchronized void produce() throws InterruptedException {
            int val = 0;
            while (true) {
                while (list.size() == capacity) {
                    wait();
                }
                System.out.println("Producer Produced : " + val);
                list.add(val);
                val++;
                notify();
                Thread.sleep(1000);
            }
        }
    
        synchronized void consume() throws InterruptedException {
            while (true) {
                while (list.size() == 0) {
                    wait();
                }
                int val;
                val = list.removeFirst();
                System.out.println("Consumer consumed-" + val);
                notify();
                Thread.sleep(1000);
            }
        }
    }
    
    class a extends Thread {
        fun f;
        a(fun f) {
            this.f = f;
        }
        public void run() {
            try {
                f.produce();
            } catch (InterruptedException e) {
                System.out.println(e);
            }
        }
    }
    
    class b extends Thread {
        fun f;
        b(fun f) {
            this.f = f;
        }
        public void run() {
            try {
                f.consume();
            } catch (InterruptedException e) {
                System.out.println(e);
            }
        }
    }