Results 1 to 13 of 13
  1. #1
    Java101 is offline Member
    Join Date
    Jan 2012
    Posts
    8
    Rep Power
    0

    Default "Producer Consumer" Integer Buffer

    Hi, I'm trying to understand the Reentrant Lock :

    From what I've read, only one thread can "hold" the lock at any given time.
    The following code sets up an Integer buffer which generates 1 integer, waits for another thread to read it, then generates another etc.
    In order for the following code to work, wouldn't 1 "consumer" and 1 "producer" need to hold the lock simultaneously?
    I've followed an example and my code works, I'm just curious as to why!

    Any advice, including comments on how I could improve my code, would be greatly appreciated :)

    Java Code:
    public class ProducerConsumerDriver {
    
    	public static void main ( String args[]) {
    		IntBuffer ib = new IntBuffer();
    		Producer p1 = new Producer(ib);
    		Producer p2 = new Producer(ib);
    		Consumer c1 = new Consumer(ib);
    		Consumer c2 = new Consumer(ib);
    		
    		p1.start();
    		p2.start();
    		c1.start();
    		c2.start();
    	}
    
    }

    Java Code:
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class IntBuffer {
    	private int contents;
    	private final ReentrantLock lock = new ReentrantLock(true); //implements fairness
    	private boolean available = false;
    	final Condition intProduced = lock.newCondition(); 			
    	final Condition intConsumed = lock.newCondition();
    	
    	
    	public int get(int ID) {
    		lock.lock();
    		
    		try {	
    			while(available == false) {		
    				intProduced.await();					//if no new Int is available, wait for a producer to make one	
    			}
    			available = false;							//the new int is about to be consumed (method is locked so no other threads can interrupt) so we can let the producer provide a new int
    			intConsumed.signal();						//signal to producer that the int has been consumed
    			System.out.println("Consumer #" + ID + " got: " + contents);	
    			return contents;							//return(consume) the produced value	
    			
    		} catch (Exception e) {
    			e.printStackTrace();
    			return contents;							//return the produced value	
    		}
    		finally {
    			lock.unlock();								//unlock to allow next consumer to wait for an int
    		}
    	} 
    		
    	public void put(int value, int ID) {
    		lock.lock();
    		
    		try {
    			while(available == true) {
    				intConsumed.await();									// wait for consumer to take value
    			}
    
    			contents = value;											//once the consumer has taken a value put a new one in the buffer
    			System.out.println("Producer #" + ID + " put: " + contents);
    			available = true;	
    			intProduced.signal();										//indicate that a new int is available in the buffer
    			
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		finally {
    			lock.unlock();			
    		}
    	}
    	
    }
    Java Code:
    public class Producer extends Thread {
    	private IntBuffer cubbyhole;
    	private int prodID;
    	private static int numOfProd;
    	
    	public Producer(IntBuffer c) {
    		cubbyhole = c;
    		prodID = ++numOfProd;
    	}
    	
    	public void run() {
    		for (int i = 0; i < 10; i++) {
    			cubbyhole.put(i, prodID);
    			try {
    				sleep((int)(Math.random() * 100));
    			} 
    			catch (InterruptedException e) { }
    		}
    	}
    }
    Java Code:
    public class Consumer extends Thread {
    	private IntBuffer cubbyhole;
    	private int consumID;
    	private static int numOfConsum;
    	
    	public Consumer(IntBuffer c) {
    		cubbyhole = c;
    		consumID = ++numOfConsum;
    	}
    	
    	public void run() {
    		for (int i = 0; i < 10; i++) {
    			cubbyhole.get(consumID);
    		}
    	}
    }
    Last edited by Java101; 01-20-2012 at 06:13 PM.

  2. #2
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,305
    Rep Power
    25

    Default Re: "Producer Consumer" Integer Buffer

    Try debugging your code by adding lots of printlns that show the execution flow and the values of variables as they change.
    The printout will help you understand how the code is executing.

  3. #3
    Java101 is offline Member
    Join Date
    Jan 2012
    Posts
    8
    Rep Power
    0

    Default Re: "Producer Consumer" Integer Buffer

    I've already done that when I wrote it originally but I'm still not sure.

    For example, If a "Consumer" thread calls the get method initially, it waits until the put method has been called by the "Producer"
    Doesn't consumer still hold the lock while the producer calls the put method? which also requires the lock?

    It's probably very straightforward but there is just something I'm missing!

  4. #4
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,305
    Rep Power
    25

    Default Re: "Producer Consumer" Integer Buffer

    Only one thread should hold the lock. The other thread queues waiting to get the lock.

    What is printed out if you add printlns to show how the different threads get the lock and release it.

  5. #5
    Java101 is offline Member
    Join Date
    Jan 2012
    Posts
    8
    Rep Power
    0

    Default Re: "Producer Consumer" Integer Buffer

    With print debugging code:
    Java Code:
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class IntBuffer {
    	private int contents;
    	private final ReentrantLock lock = new ReentrantLock(true); //implements fairness
    	private boolean available = false;
    	final Condition intProduced = lock.newCondition(); 			
    	final Condition intConsumed = lock.newCondition();
    	
    	
    	public int get(int ID) {
    		lock.lock();
    		System.out.printf("Consumer %d has lock\n", ID);
    		
    		try {	
    			while(available == false) {		
    				System.out.printf("Consumer %d has lock, waiting for producer to provide new int\n", ID);
    				intProduced.await();					//if no new Int is available, wait for a producer to make one	
    			}
    			
    			return contents;							//return(consume) the produced value	
    			
    		} catch (Exception e) {
    			e.printStackTrace();
    			return contents;							//return the produced value	
    		}
    		finally {
    			System.out.println("Consumer #" + ID + " got: " + contents);	
    			available = false;							//the new int is about to be consumed (method is locked so no other threads can interrupt) so we can let the producer provide a new int
    			System.out.printf("Consumer %d has lock, signals to producer that new int has been consumed\n", ID);
    			intConsumed.signal();						//signal to producer that the int has been consumed
    			System.out.printf("Consumer %d releases lock\n", ID);
    			lock.unlock();								//unlock to allow next consumer to wait for an int
    		}
    	} 
    		
    	public void put(int value, int ID) {
    		lock.lock();
    		System.out.printf("Producer %d has lock\n", ID);
    		
    		try {
    			while(available == true) {
    				System.out.printf("Producer %d has lock, waiting for consumer to take value\n", ID);
    				intConsumed.await();									// wait for consumer to take value
    			}
    
    			contents = value;											//once the consumer has taken a value put a new one in the buffer
    			System.out.println("Producer #" + ID + " put: " + contents);
    			available = true;	
    			System.out.printf("Producer %d has lock, signals to consumer that new int is ready\n", ID);
    			intProduced.signal();										//indicate that a new int is available in the buffer
    			
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		finally {
    			System.out.printf("Producer %d releases lock\n", ID);
    			lock.unlock();			
    		}
    	}
    	
    }
    Quote Originally Posted by Output
    Producer 1 has lock
    Producer #1 put: 0
    Producer 1 has lock, signals to consumer that new int is ready
    Producer 1 releases lock
    Producer 2 has lock
    Producer 2 has lock, waiting for consumer to take value
    Consumer 1 has lock <--------- How can consumer 1 have the lock if Producer 2 hasn't released it yet?
    Consumer #1 got: 0
    Consumer 1 has lock, signals to producer that new int has been consumed
    Consumer 1 releases lock
    Consumer 2 has lock
    Consumer 2 has lock, waiting for producer to provide new int
    Producer #2 put: 0
    Producer 2 has lock, signals to consumer that new int is ready
    Producer 2 releases lock
    Consumer 1 has lock
    Consumer #1 got: 0
    Consumer 1 has lock, signals to producer that new int has been consumed
    Consumer 1 releases lock
    Consumer 2 has lock, waiting for producer to provide new int
    Consumer 1 has lock
    Consumer 1 has lock, waiting for producer to provide new int
    Producer 2 has lock
    Producer #2 put: 1
    Producer 2 has lock, signals to consumer that new int is ready
    Producer 2 releases lock
    Consumer #2 got: 1
    Consumer 2 has lock, signals to producer that new int has been consumed
    Consumer 2 releases lock
    Consumer 2 has lock
    Consumer 2 has lock, waiting for producer to provide new int
    Producer 1 has lock
    Producer #1 put: 1
    Producer 1 has lock, signals to consumer that new int is ready
    Producer 1 releases lock
    Consumer #1 got: 1
    Consumer 1 has lock, signals to producer that new int has been consumed
    Consumer 1 releases lock
    Consumer 1 has lock
    Consumer 1 has lock, waiting for producer to provide new int
    Producer 2 has lock
    Producer #2 put: 2
    Producer 2 has lock, signals to consumer that new int is ready
    Producer 2 releases lock
    Consumer #2 got: 2
    Consumer 2 has lock, signals to producer that new int has been consumed
    Consumer 2 releases lock
    Consumer 2 has lock
    Consumer 2 has lock, waiting for producer to provide new int
    Producer 1 has lock
    Producer #1 put: 2
    Producer 1 has lock, signals to consumer that new int is ready
    Producer 1 releases lock
    Consumer #1 got: 2
    Consumer 1 has lock, signals to producer that new int has been consumed
    Consumer 1 releases lock
    Consumer 1 has lock
    Consumer 1 has lock, waiting for producer to provide new int
    Producer 1 has lock
    Producer #1 put: 3
    Producer 1 has lock, signals to consumer that new int is ready
    Producer 1 releases lock
    Consumer #2 got: 3
    Consumer 2 has lock, signals to producer that new int has been consumed
    Consumer 2 releases lock
    Consumer 2 has lock
    Consumer 2 has lock, waiting for producer to provide new int
    Producer 2 has lock
    Producer #2 put: 3
    Producer 2 has lock, signals to consumer that new int is ready
    Producer 2 releases lock
    Consumer #1 got: 3
    Consumer 1 has lock, signals to producer that new int has been consumed
    Consumer 1 releases lock
    Consumer 1 has lock
    Consumer 1 has lock, waiting for producer to provide new int
    Producer 1 has lock
    Producer #1 put: 4
    Producer 1 has lock, signals to consumer that new int is ready
    Producer 1 releases lock
    Consumer #2 got: 4
    Consumer 2 has lock, signals to producer that new int has been consumed
    Consumer 2 releases lock
    Consumer 2 has lock
    Consumer 2 has lock, waiting for producer to provide new int
    Producer 1 has lock
    Producer #1 put: 5
    Producer 1 has lock, signals to consumer that new int is ready
    Producer 1 releases lock
    Consumer #1 got: 5
    Consumer 1 has lock, signals to producer that new int has been consumed
    Consumer 1 releases lock
    Consumer 1 has lock
    Consumer 1 has lock, waiting for producer to provide new int
    Producer 1 has lock
    Producer #1 put: 6
    Producer 1 has lock, signals to consumer that new int is ready
    Producer 1 releases lock
    Consumer #2 got: 6
    Consumer 2 has lock, signals to producer that new int has been consumed
    Consumer 2 releases lock
    Consumer 2 has lock
    Consumer 2 has lock, waiting for producer to provide new int
    Producer 2 has lock
    Producer #2 put: 4
    Producer 2 has lock, signals to consumer that new int is ready
    Producer 2 releases lock
    Consumer #1 got: 4
    Consumer 1 has lock, signals to producer that new int has been consumed
    Consumer 1 releases lock
    Consumer 1 has lock
    Consumer 1 has lock, waiting for producer to provide new int
    Producer 2 has lock
    Producer #2 put: 5
    Producer 2 has lock, signals to consumer that new int is ready
    Producer 2 releases lock
    Consumer #2 got: 5
    Consumer 2 has lock, signals to producer that new int has been consumed
    Consumer 2 releases lock
    Consumer 2 has lock
    Consumer 2 has lock, waiting for producer to provide new int
    Producer 1 has lock
    Producer #1 put: 7
    Producer 1 has lock, signals to consumer that new int is ready
    Producer 1 releases lock
    Consumer #1 got: 7
    Consumer 1 has lock, signals to producer that new int has been consumed
    Consumer 1 releases lock
    Consumer 1 has lock
    Consumer 1 has lock, waiting for producer to provide new int
    Producer 2 has lock
    Producer #2 put: 6
    Producer 2 has lock, signals to consumer that new int is ready
    Producer 2 releases lock
    Consumer #2 got: 6
    Consumer 2 has lock, signals to producer that new int has been consumed
    Consumer 2 releases lock
    Consumer 2 has lock
    Consumer 2 has lock, waiting for producer to provide new int
    Producer 1 has lock
    Producer #1 put: 8
    Producer 1 has lock, signals to consumer that new int is ready
    Producer 1 releases lock
    Consumer #1 got: 8
    Consumer 1 has lock, signals to producer that new int has been consumed
    Consumer 1 releases lock
    Consumer 1 has lock
    Consumer 1 has lock, waiting for producer to provide new int
    Producer 1 has lock
    Producer #1 put: 9
    Producer 1 has lock, signals to consumer that new int is ready
    Producer 1 releases lock
    Consumer #2 got: 9
    Consumer 2 has lock, signals to producer that new int has been consumed
    Consumer 2 releases lock
    Consumer 2 has lock
    Consumer 2 has lock, waiting for producer to provide new int
    Producer 2 has lock
    Producer #2 put: 7
    Producer 2 has lock, signals to consumer that new int is ready
    Producer 2 releases lock
    Consumer #1 got: 7
    Consumer 1 has lock, signals to producer that new int has been consumed
    Consumer 1 releases lock
    Producer 2 has lock
    Producer #2 put: 8
    Producer 2 has lock, signals to consumer that new int is ready
    Producer 2 releases lock
    Consumer #2 got: 8
    Consumer 2 has lock, signals to producer that new int has been consumed
    Consumer 2 releases lock
    Consumer 2 has lock
    Consumer 2 has lock, waiting for producer to provide new int
    Producer 2 has lock
    Producer #2 put: 9
    Producer 2 has lock, signals to consumer that new int is ready
    Producer 2 releases lock
    Consumer #2 got: 9
    Consumer 2 has lock, signals to producer that new int has been consumed
    Consumer 2 releases lock
    From the output it still appears that 2 threads have the same lock simultaneously?

  6. #6
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,305
    Rep Power
    25

    Default Re: "Producer Consumer" Integer Buffer

    If the producer holds the lock and that prevents a consumer from getting the lock, isn't that a deadlock condition?
    The producer calls the await method and waits until being notified that the consumer has gotten the data.

    Read the API doc for what the newCondition method does and what the Condition class does.

  7. #7
    Java101 is offline Member
    Join Date
    Jan 2012
    Posts
    8
    Rep Power
    0

    Default Re: "Producer Consumer" Integer Buffer

    I understand that its a deadlock situation, as the Consumer might be waiting for the Producer to produce while the Producer is also waiting for the consumer to consume, hence why the Condition class was needed.

    From the API:
    newCondition()
    Quote Originally Posted by newCondition()
    "A call to Condition.await() will atomically release the lock before waiting and re-acquire the lock before the wait returns."
    I now understand that only 1 thread actually holds the lock at any time, however, for example, when await() is called and the lock is temporarily released, what is to stop another waiting thread from acquiring the lock? (see line 13) "lock.lock();"

  8. #8
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,305
    Rep Power
    25

    Default Re: "Producer Consumer" Integer Buffer

    Yes another thread can get the lock and the thread that is waiting will stay waiting until that other thread releases the lock.

  9. #9
    Java101 is offline Member
    Join Date
    Jan 2012
    Posts
    8
    Rep Power
    0

    Default Re: "Producer Consumer" Integer Buffer

    So would that not mean the following is possible?

    Producer thread #1 gets lock
    Producer thread #1 await()
    Producer thread #2 gets temporarily released lock
    Producer thread #2 await() on same condition as Producer thread #1

    Consumer thread #1 gets temporarily released lock
    Consumer thread #1 consumes int and signals the condition which Producer thread #1 and Producer thread #2 are both waiting on...

    Which Producer will then acquire the lock?

  10. #10
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,305
    Rep Power
    25

    Default Re: "Producer Consumer" Integer Buffer

    The Lock class will decide.
    new ReentrantLock(true); //implements fairness

  11. #11
    Java101 is offline Member
    Join Date
    Jan 2012
    Posts
    8
    Rep Power
    0

    Default Re: "Producer Consumer" Integer Buffer

    Ahh I see now, it actually doesn't matter how many threads are in await() as each one is still relying on "available" along with the condition signal.

    Thanks very much for your help and patience Norm

  12. #12
    Norm's Avatar
    Norm is offline Moderator
    Join Date
    Jun 2008
    Location
    SW Missouri
    Posts
    17,305
    Rep Power
    25

    Default Re: "Producer Consumer" Integer Buffer

    You're welcome. I learned a bit about the new classes myself.

  13. #13
    DesChambers is offline Member
    Join Date
    Jan 2012
    Posts
    1
    Rep Power
    0

    Default Re: "Producer Consumer" Integer Buffer

    You're dead right! Spot on. This is plagiarism however.
    Last edited by DesChambers; 01-26-2012 at 06:15 PM. Reason: Humour added

Similar Threads

  1. Consumer/Producer with random numbers
    By devo22 in forum Threads and Synchronization
    Replies: 1
    Last Post: 11-13-2011, 06:57 PM
  2. producer/consumer problem
    By concaf in forum Threads and Synchronization
    Replies: 1
    Last Post: 09-20-2011, 02:07 PM
  3. Producer-Consumer Problem
    By kendel in forum Threads and Synchronization
    Replies: 1
    Last Post: 03-04-2011, 01:09 PM
  4. Producer Consumer Synchronization Problem
    By rushhour in forum Threads and Synchronization
    Replies: 3
    Last Post: 11-23-2010, 07:44 PM
  5. Replies: 1
    Last Post: 10-20-2008, 07:35 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •