0

To understand how multi threading works I am using Queue and ReentrantLock to simulate Producer and Consumer problem. My Producer thread is adding data into the queue but Consumer is not removing. I am not sure if I have implemented it correctly.

producer class

package concurrency;

import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;


class Producer implements Runnable{
    Queue<Integer> list;
    Condition con;
    ReentrantLock lock;
    int size;


    Producer(Queue q1, Condition con, ReentrantLock l1,int size)
    {
        this.list=q1;
        this.con=con;
        this.lock=l1;
        this.size=size;
    }

    public void run()
    {
        for(int i =0;i<20;i++)
        {
            if(lock.tryLock())
            {
                while(list.size()==size)
                {
                    try 
                    {
                        con.await();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                list.add(i);
                System.out.println("Producer "+ Thread.currentThread() +"added "+i+" to the List" );
                con.signalAll();
                lock.unlock();

            }
        }
    }
}

consumer class

class Consumer implements Runnable{
    Queue<Integer> list;
    Condition con;
    ReentrantLock lock;
    int size;

    Consumer(Queue q1, Condition con, ReentrantLock l1,int size)
    {
        this.list=q1;
        this.con=con;
        this.lock=l1;
        this.size=size;
    }

    public void run()
    {

        for(int innerLoop =0;innerLoop<20;innerLoop++){
            if(lock.tryLock()){
                while(list.size()<1){
                    try {
                        con.await();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                int i = (int) list.remove();
                System.out.println("Consumer "+ Thread.currentThread() +"removed "+i+"  from the List" );
                con.signalAll();
                lock.unlock();
            }
        }
    }
}

shared resource class

class SharedResource {

    Queue list ;
    
    Condition con;
    ReentrantLock lock;
    int size;

    SharedResource()
    {
        size =20;
        this.list=new LinkedList<Integer>();
        lock = new ReentrantLock();
        this.con = lock.newCondition();
    }
    
    public Queue getList() {
        return list;
    }

    public void setList(Queue list) {
        this.list = list;
    }

    public Condition getCon() {
        return con;
    }

    public void setCon(Condition con) {
        this.con = con;
    }

    public ReentrantLock getLock() {
        return lock;
    }

    public void setLock(ReentrantLock lock) {
        this.lock = lock;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

}

runnable class

public class MYPRODUCERCONSUMER {

    public static void main(String[] args) {

        SharedResource producerCObj = new SharedResource();
        Producer producer= new Producer(producerCObj.getList(), producerCObj.getCon(), producerCObj.getLock(), producerCObj.getSize());
        Thread producerThread= new Thread(producer);
        producerThread.start();

        Consumer consumer= new Consumer(producerCObj.getList(), producerCObj.getCon(), producerCObj.getLock(), producerCObj.getSize());
        Thread consumerThread= new Thread(consumer);
        consumerThread.start();
    }

}
giannis christofakis
  • 8,201
  • 4
  • 54
  • 65
crazyStart
  • 127
  • 1
  • 10
  • Start by realizing there's no point to doing locking here. ArrayBlockingQueue is threadsafe and makes threads block when there's nothing there for them to do. You can delete all the stuff with locks and conditions. – Nathan Hughes Oct 13 '16 at 14:26
  • 1
    @Nathan Hughes I want to understand how to work with lock and conditions so I have changed ArrayBlockingQueue to LinkedList . – crazyStart Oct 13 '16 at 14:34

1 Answers1

1

In your consumer you try to acquire lock:

if(lock.tryLock())

But tryLock acquires the lock only if it is not held by another thread at the time of invocation. Just because you start producer first it is highly likely that it is already acquired by Producer. You try to do unlock but next instruction is tryLock (in a loop) so there is no any sort of yield for other thread. In other words Consumer thread almost has no chance to acquire lock because Producer thread reacquires it. And just because you have finite loop (only 20) your Consumer just finishes.

If you add

class Producer implements Runnable {

    Queue<Integer> list;
    Condition con;
    ReentrantLock lock;
    int size;

    Producer(Queue q1, Condition con, ReentrantLock l1,int size)
    {
        this.list=q1;
        this.con=con;
        this.lock=l1;
        this.size=size;
    }

    public void run()
    {
        for(int i =0;i<20;i++)
        {
            if(lock.tryLock())
            {
                while(list.size()==size)
                {
                    try
                    {
                        con.await();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                list.add(i);
                System.out.println("Producer "+ Thread.currentThread() +"added "+i+" to the List" );
                con.signalAll();
                lock.unlock();

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

after

 lock.unlock();

in your Producer loop you will give chance to Consumer thread to acquire lock and you will get result as expected.

giannis christofakis
  • 8,201
  • 4
  • 54
  • 65
Mike Shauneu
  • 3,201
  • 19
  • 21