Mastering the use of Condition interface in Concurrent Programming Series

Mastering the use of Condition interface in Concurrent Programming Series

1. What is a Condition interface

Condition is the concurrent wait api provided in the juc package of jdk, commonly known as conditional wait. Condition variable is used to provide the wait/notify wait notification mode of synchronized plus Object in Lock.

Note that Condition is only an api interface, and the specific implementation still depends on the specific lock class. For example, use new ReentrantLock().newCondition();

  • wait(), notify(), notifyAll() in Object can be used together with synchronized to wake up one or all
  • Condition needs to be used in conjunction with lock implementation class. A lock instance can create multiple conditions, one condition and one waiting set, which can accurately control the waiting thread according to the conditions

Multithreaded read queue. After writing data, wake up the read thread to continue execution. After reading the data, wake up the write thread to continue execution

2. Common methods of Condition interface

Use the idea editor to view the Condition method, as shown in the figure:

  • await(): the current thread is waiting until it receives a signal or is interrupted
  • await(long time, TimeUnit unit): the current thread is waiting until it receives a signal, is interrupted, or reaches the specified waiting time.
  • awaitNanos(long nanosTimeout): the current thread is waiting until it receives a signal, is interrupted, or reaches the specified waiting time. The return value indicates the remaining time. If you wake up before nanosTimesout, the return value = nanosTimeout - time consumption. If the return value < = 0, it can be considered that it has timed out.
  • Awaituninterruptible(): the current thread is waiting until it receives the signal. This method is not sensitive to interrupts
  • awaitUntil(Date deadline): the current thread is waiting until it receives a signal, is interrupted, or reaches the specified deadline. If you are notified before the specified time, return true; otherwise, return false.
  • signal(): wakes up a waiting thread. The thread must obtain a Condition related lock before returning from the wait method.
  • signal()All: wake up all waiting threads. A thread that can return from a wait method must obtain a Condition related lock.

2. Condition example

Using Condition to realize producer consumer mode:

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

public class ConditionLockQueue {

    private LinkedList<Object> queue;
    private volatile int capacity;
    private Condition productCondition = null;
    private Condition consumeCondition = null;
    private Lock lock;

    public ConditionLockQueue(int capacity) {
        this.queue = new LinkedList<Object>();
        this.capacity = capacity;
        lock = new ReentrantLock();
        this.productCondition  = lock.newCondition();
        this.consumeCondition = lock.newCondition();
    }

    public void put(Object obj) throws InterruptedException {
        lock.lock();
        try {
            while (queue.size() == capacity) {
                productCondition.await();
                System.out.println("The product warehouse is full and cannot be produced!");
            }
            queue.add(obj);
            System.out.println("[Producer]: " + obj+ ",share:"+queue.size());
            consumeCondition.signal();
        } finally {
            lock.unlock();
        }
    }

    public Object sub() throws InterruptedException {
        Object obj = null;
        lock.lock();
        try {
            while (queue.size() == 0) {
                consumeCondition.await();
                System.out.println("There is no product, need to produce!");
            }
            Object prod =  queue.remove(0);
            System.out.println("[Consumer]: " + prod + ",share:"+queue.size());
            productCondition.signal();
        }finally {
            lock.unlock();
        }
        return obj;
    }

    public boolean isEmpty() {
        return (queue.size() == 0);
    }


    public static void main(String[] args) throws InterruptedException {
        Random random = new Random();
        ConditionLockQueue queue = new ConditionLockQueue(10);
        Runnable produceTask = () -> {
            for (; ;) {
                try {
                    queue.put(random.nextInt(10));
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Runnable consumeTask = () -> {
            for (; ;) {
                try {
                    queue.sub();
                    Thread.sleep(random.nextInt(100));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        //3 Producers
        new Thread(produceTask).start();
        new Thread(produceTask).start();
        new Thread(produceTask).start();
        //3 consumers
        new Thread(consumeTask).start();
        new Thread(consumeTask).start();
        new Thread(consumeTask).start();

    }

}

Appendix references

Posted on Fri, 03 Dec 2021 22:27:40 -0500 by raydar2000