Java Condition Interface

Condition interface which resides in java.util.concurrent.locks has methods for inter thread communication similar to Object class monitor methods (wait, notify and notifyAll). Condition provides methods like await(), signal(), signalAll(). Where a Lock replaces the use of synchronized methods and statements, a Condition replaces the use of the Object monitor methods.

Some of the methods defined in java.util.concurrent.locks.Condition interface are given below.

  • await()– Causes the current thread to wait until it is signalled or interrupted.
  • await(long time, TimeUnit unit)– Causes the current thread to wait until it is signalled or interrupted, or the specified waiting time elapses.
  • awaitNanos(long nanosTimeout)– Causes the current thread to wait until it is signalled or interrupted, or the specified waiting time elapses.
  • awaitUninterruptibly()– Causes the current thread to wait until it is signalled.
  • awaitUntil(Date deadline)– Causes the current thread to wait until it is signalled or interrupted, or the specified deadline elapses.
  • signal()– Wakes up one waiting thread.
  • signalAll()– Wakes up all waiting threads.

How to get Condition instance

A Condition instance is intrinsically bound to a lock. To obtain a Condition instance for a particular Lock instance use its newCondition() method.

Example using Condition interface methods

Following producer consumer program uses the methods of the Condition interface for intercommunication between two threads.
In the example Consumer thread starts removing items from buffer only when buffer is full till then the Consumer thread is in wait state because of await() method.

package com.knpcode.proj.Programs;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ProduceConsume {
  public static void main(String[] args) {
    int capacity = 5;
    // shared object
    Buffer buffer = new Buffer(capacity);
    Thread t1 = new Thread(new Producer(buffer, capacity), "Producer");
    Thread t2 = new Thread(new Consumer(buffer, capacity), "Consumer");
    t1.start();
    t2.start(); 
  }

  // Producer class to add elements to buffer
  static class Producer implements Runnable{
    Buffer buffer;
    int capacity;
    Producer(Buffer buffer, int capacity){
      this.buffer = buffer;
      this.capacity = capacity;
    }
    @Override
    public void run() {
      for(int i = 1; i <= capacity; i++){
        try {
          buffer.put(i);
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }
  }
  // Consumer class to remove elements from buffer
  static class Consumer implements Runnable{
    Buffer buffer;
    int capacity;
    Consumer(Buffer buffer, int capacity){
      this.buffer = buffer;
      this.capacity = capacity;
    }
    
    @Override
    public void run() {
      for(int i = 1; i <= capacity; i++){
        try {
          System.out.println("Item removed- " + buffer.take());
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }
  }
	
  static class Buffer {
    private Object[] items;
    final Lock lock = new ReentrantLock();
    // Conditions
    final Condition notFull  = lock.newCondition(); 
    final Condition notEmpty = lock.newCondition(); 
    int putptr, takeptr, count;
    public Buffer(int capacity){
      items = new Object[capacity];
    }
		
    public void put(Object x) throws InterruptedException {
      lock.lock();
      try {
        while (count == items.length)
          notFull.await();
        items[putptr] = x;
        System.out.println("Putting- "+ x);
        if (++putptr == items.length) { 
          putptr = 0;
        }
        ++count;
        notEmpty.signal();
      } finally {
        lock.unlock();
      }
    }

    public Object take() throws InterruptedException {
      lock.lock();
      try {
        while (count == 0) {
          notEmpty.await();
        }
        Object item = items[takeptr];
        if (++takeptr == items.length) {
          takeptr = 0;
        }
        --count;
        notFull.signal();
        return item;
      } finally {
        lock.unlock();
      }
    }
  }
}

Output

Putting- 1
Putting- 2
Putting- 3
Putting- 4
Putting- 5
Item removed- 1
Item removed- 2
Item removed- 3
Item removed- 4
Item removed- 5

Related Posts

That’s all for the topic Java Condition Interface. If something is missing or you have something to share about the topic please write a comment.


You may also like

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.