一、概述

  任何一个Java对象,都拥有一组监视器方法,主要包括wait()、notify()、notifyAll()方法,这些方法与synchronized关键字配合使用可以实现等待/通知机制。使用这种方式实现了生产者-消费者模式。

  类似地,Condition接口也提供类似的Object的监视器的方法,主要包括await()、signal()、signalAll()方法,这些方法与Lock锁配合使用也可以实现等待/通知机制。

1.1、对比object监视器

对比项 Object监视器 Condition
前置条件 获取对象的锁 调用Lock.lock获取锁,调用Lock.newCondition获取Condition对象
调用方式 直接调用,比如object.notify() 直接调用,比如condition.await()
等待队列的个数 一个 多个
当前线程释放锁进入等待状态 支持 支持
当前线程释放锁进入等待状态,在等待状态中不断响中断 不支持 支持
当前线程释放锁并进入超时等待状态 支持 支持
当前线程释放锁并进入等待状态直到将来的某个时间 不支持 支持
唤醒等待队列中的一个线程 支持 支持
唤醒等待队列中的全部线程 支持 支持

1.2、Condition接口定义

public interface Condition {

    // 使当前线程处于等待状态,释放与Condtion绑定的lock锁
    // 直到 singal()方法被调用后,被唤醒(若中断,就game over了)
    // 唤醒后,该线程会再次获取与条件绑定的 lock锁
    void await() throws InterruptedException;

    // 相比较await()而言,不响应中断
    void awaitUninterruptibly();

    // 在wait()的返回条件基础上增加了超时响应,返回值表示当前剩余的时间
    // < 0 ,则表示超时
    long awaitNanos(long nanosTimeout) throws InterruptedException;

    // 同上,只是时间参数不同而已
    boolean await(long time, TimeUnit unit) throws InterruptedException;

    // 同上,只是时间参数不同而已
    boolean awaitUntil(Date deadline) throws InterruptedException;

    // 表示条件达成,唤醒一个被条件阻塞的线程
    void signal();

    // 唤醒所有被条件阻塞的线程。
    void signalAll();
}

Condition的使用小结:

  • Condition与Lock配套使用,通过 Lock#newConditin() 进行实例化
  • Condition#await() 会释放lock,线程阻塞;直到线程中断or Condition#singal()被执行,唤醒阻塞线程,并重新获取lock
  • 经典case可以参考jdk的阻塞队列实现(ArrayBlockingQueue, LinkedBlockingQueue)

 后续可以分析:ArrayBlockingQueue, LinkedBlockingQueue实现

1.3、使用Condition接口配合Lock锁的使用实例如下

   Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public void conditionWait() throws InterruptedException {
        lock.lock();
        try {
            //....
            condition.await();
        }finally {
            lock.unlock();
        }
    }

    public void conditionSignal(){
        lock.lock();
        try {
            //...
            condition.signal();
        }finally {
            lock.unlock();
        }
    }

  一般而言,都会将Condition变量作为成员变量。当调用await方法后,当前线程会释放锁并进入Condition变量的等待队列,而其他线程调用signal方法后,通知正在Condition变量等待队列的线程从await方法返回,并且在返回前已经获得了锁。

1.4、示例

package com.lhx.cloud.threadlock;

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

/**
 * @author lihongxu
 * @desc @link(https://github.com/bjlhx15/common-study)
 * @since 2019/3/26 下午4:23
 */
public class SampleQueue<T> {
    private Object[] elements;
    private Lock lock=new ReentrantLock();
    //队列是否为空
    private Condition notEmpty = lock.newCondition();
    //队列是否已满
    private Condition notFull = lock.newCondition();
    private int length=0,addIndex=0,removeIndex=0;

    public SampleQueue(int size) {
        this.elements = new Object[size];
    }

    public int getLength() {
        return length;
    }

    public void add(T object) throws InterruptedException {
        lock.lock();
        try {
            while (length==elements.length){
                System.out.println("队列已满,等待~~~");
                notFull.await();
            }
            elements[addIndex]=object;
            if(addIndex++ ==elements.length){
                addIndex = 0;
            }
            length++;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }
    public T remove() throws InterruptedException {
        lock.lock();
        try {
            while (length==0){
                System.out.println("队列为空,等待~~~");
                notEmpty.await();
            }
            Object element = elements[removeIndex];
            if(removeIndex++ ==elements.length){
                removeIndex = 0;
            }
            length--;
            notFull.signal();
            return (T) element;
        } finally {
            lock.unlock();
        }
    }
}
View Code

相关文章:

  • 2021-08-08
  • 2021-09-03
  • 2021-08-02
  • 2022-01-05
  • 2022-01-10
  • 2021-09-12
  • 2021-07-16
猜你喜欢
  • 2021-06-16
  • 2022-02-17
  • 2022-12-23
  • 2021-06-21
  • 2021-10-28
相关资源
相似解决方案