The role of condition in lock

The Condition interface is a mechanism provided by the Lock interface, which can help us communicate in an orderly manner between threads. When a thread needs to wait for a certain condition to be met, it can call the await method of Condition to make the thread enter the waiting state. When another thread meets the corresponding condition, you can call the signal or signalAll method of Condition to wake up the corresponding thread.

The following is an example of using Condition to implement thread communication:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyQueue<T> {
    
    
    private final Object[] items;
    private int head;
    private int tail;
    private int count;
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    public MyQueue(int capacity) {
    
    
        items = new Object[capacity];
    }
    public void put(T item) throws InterruptedException {
    
    
        lock.lock();
        try {
    
    
            while (count == items.length) {
    
    
                notFull.await();
            }
            items[tail] = item;
            if (++tail == items.length) {
    
    
                tail = 0;
            }
            count++;
            notEmpty.signalAll();
        } finally {
    
    
            lock.unlock();
        }
    }
    public T take() throws InterruptedException {
    
    
        lock.lock();
        try {
    
    
            while (count == 0) {
    
    
                notEmpty.await();
            }
            Object item = items[head];
            if (++head == items.length) {
    
    
                head = 0;
            }
            count--;
            notFull.signalAll();
            return (T) item;
        } finally {
    
    
            lock.unlock();
        }
    }
}

In the above example, we implemented a simple queue class MyQueue, using ReentrantLock and Condition to realize the communication between threads. Among them, notFull and notEmpty represent the condition that the queue is not full and not empty respectively.

In the put method, when the queue is full, the thread will call notFull.await() to enter the waiting state until another thread calls notEmpty.signalAll(). Before releasing the lock, we need to use lock.unlock().

In the take method, when the queue is empty, the thread will call notEmpty.await() to enter the waiting state until another thread calls notFull.signalAll(). Before the method returns, we need to use lock.unlock().

It should be noted that using Condition to implement thread communication needs to be carried out under the protection of Lock. The system call condition variable needs to acquire a lock so that there are no race conditions.

Note:
Because the thread will call the await method when the waiting condition is met, this method will cause the thread to release the lock and enter the waiting state until other threads call the corresponding signal or signalAll method to wake it up. In this example, when the queue is full, the thread calls notFull.await() to wait until another thread calls notEmpty.signalAll() to wake it up.
Therefore, when using Condition to implement communication between threads, we need to call the corresponding method at the right time to ensure the correctness of the thread and avoid the occurrence of an infinite loop.

Guess you like

Origin blog.csdn.net/weixin_43031220/article/details/130655170