在 JavaSE5 中新添加了 java.util.concurrent.locks. Condition 接口。

主要包括 await、signal、signalAll 方法来实现休眠和唤醒工作,有点类似与Linux C++的信号通信机制。

Condition 不仅在 API 中实现了 wait/notify 语义,而且提供了几个新的特性,

例如:为每个 Lock 创建多重 Condition、可中断的等待、访问统计信息等。

 

1、Condition的概念

Condition: Condition接口提供了类似Object的监视器Monitor方法,与Lock配合可以实现等待/通知模式。

当前线程若要调用Condition的相关方法,需要提前获取到Condition对象关联的锁,

Condition对象是由Lock对象的newCondition()创建出来的。Condition是依赖于Lock对象的

等待方法

1、void await() throws InterruptedException;

同Object.wait(),直到被中断或唤醒(死等),如果在等待状态中被其他线程中断会抛出被中断异常;

2、void awaitUninterruptibly();

不响应中断,直到被唤醒(中断也不会返回)<独有>

3、boolean await(long time, TimeUnit unit) throws InterruptedException;

同Object.wait(long timeout),多了自定义时间单位,中断、超时、被唤醒都会被返回(不会死等)

4、boolean awaitUntil(Date deadline) throws InterruptedException;

支持设置截止时间<独有>

Object.wait(long timeout):这是在设置等待多久后停止等待,

而Condition.awaitUtil(Date deadline):设置的是一个截止日期,截止到这个日期时间就停止等待

唤醒方法

1、signal():唤醒一个等待在condition上的线程,将该线程由等待队列转移到同步队列上

2、signalAll():将所有等待在condition上的线程全部转移到同步队列中

 

Condition 使用实例:

public class ConditionTest {
    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();
        }
    }
}

调用await()后当前线程会释放锁并在此等待。调用signal()方法,通知当前线程后,当前线程才从await()方法返回,返回前已经获取了锁。

Condition实现的等待/通知机制与Object的等待/通知机制有什么区别?

 

2、Condition等待/通知与Object等待/通知的区别

①不同底层实现

 Object类提供的wait与noify方法是与对象监视器monitor配合完成线程的等待/通知机制,属于JVM底层实现;而Condition与Lock配合完成的等待/通知机制属于java语言级别,具有更高的控制与扩展性。

②Condition独有特性

 a) 支持不响应中断(等待队列),而Object不支持。
 b)支持多个等待队列(new 多个Condition对象),而Object只支持一个。但无论是Condition还是Object都只有一个同步队列
 c) 支持超时时间设置,而Object不支持

  到底什么才是等待队列?

  3、Condition的等待队列

等待队列概念

等待队列是一个单向的带有头尾节点的队列,所有调用condition.await()方法的线程会依次加入到该condition所对应的等待队列中,并且线程状态转换为等待状态。

Lock锁可以拥有一个同步队列和多个等待队列,Object对象监视器只能拥有一个同步队列和一个等待队列。

在这里插入图片描述

通过Condition操作实现一个有界队列

  Condition机制到底是怎么运行的?程序调用await()、signal()到底会做什么?

  4、Condition机制的流程

await()的流程(同步队列->等待队列

 当前线程调用Condition.await()实际上做了两件事情。

 a)释放当前线程的同步状态(锁)唤醒在同步队列中头结点的后继节点引用的线程。(由于当前线程是同步队列的头结点,只有头结点才有资格获取同步资源(锁))——通过AQS的release()方法

 b)将当前线程从同步队列中移出,以当前线程构造结点(addConditionWaiter),并将结点尾插入等待队列。

  PS:尾插时尾结点的更新并不需要CAS操作,因为能调用await()的线程必是获取了锁的线程)

 c)await()的结束:直到该线程再次获得了lock锁(其他线程调用signal进入同步队列+进入同步队列后那一顿操作)后,await()方法才会真正的结束,或者在等待时被中断会做中断处理。

signal()的流程(等待队列->同步队列

 若当前线程以获得线程,调用signal()就可以:将等待队列的头结点,插入同步队列的尾部,即唤醒等待时间最长的线程

 通过同步队列的流程,最终使得该线程获取到锁,才能使await()真正结束。

③signalAll的流程

 signal()只是将等待队列的头结点插入到同步队列尾部,而signalAll()是将整个等待队列依次加入到同步队列尾部。

  Condition机制的引入的原因是什么?

  5、Condition机制的应用

代替Object的wait-notify机制(该机制中的方法属于操作系统中的方法,不易于控制)

 

 

 

 

 

 

参考:

Java多线程——Condition条件

Java多线程——Condition机制

Java并发编程——Condition接口

Java并发编程——Condition(wait\signal\notify的等待-通知模式 )

 

原文: Java同步方式(3)——condition

 

 

参考推荐:

Java同步方式(2)——wait和notify/notifyall

Java 线程同步的七种方法

Java 同步关键字synchronized底层实现原理及锁优化

String、StringBuilder、StringBuffer用法比较

ArrayList、LinkedList、Vector、Map用法比较

Java类的生命周期详解

JVM优点与缺点的深入分析

Windows消息机制VC

Spring 定时任务的几种实现

MySQL 主从复制原理以及架构

阻塞和非阻塞通信

select,poll,epoll区别

Linux中select poll epoll的区别

epoll 两种触发模式

5种服务器网络编程模型讲解

Servlet 工作原理解析

Tomcat 系统架构与设计模式:工作原理

Kafka:下一代分布式消息系统

Zookeeper 工作原理