Condition 接口
系统性学习,移步IT-BLOG
Java 对象拥有一组监视方法:wait()、wait(long timeout)、notify() 以及 notifyAll() 方法,这些方法与 synchronized 同步关键字配合,可以实现等待/通知模式,进行线程之间的通讯。Condition 接口也提供了类似的方法,与 Lock 配合可以实现等待/通知模式,但两者使用方法和功能上存在差异。我们对比学习一下:
| 对比项 | Object 对象 | Condition 接口 |
| 前置条件 | 获取对象的锁 | 调用Lock.lock()获取锁,通过Lock.newCondition()获取Condition对象 |
| 调用方法 | object.wait() | condition.await() |
| 等待队列(wait queue)个数 | 一个 | 多个 |
| 当前线程释放锁并进入等待状态 | 支持 | 支持 |
| 阻塞时,响应中断interrupt() | 响应中断 | 响应中断 OR 不响应中断 |
| 当前线程释放锁,进入超时状态X(long timeout) | 支持 | 支持 |
| 当前线程释放锁并进入等待状态到将来的某个时间 | 不支持 | 支持 |
| 唤醒等待队列中的一个线程 | 支持 | 支持 |
| 唤醒等待队列中的全部线程 | 支持 | 支持 |
一、Condition 接口
当线程调用 Condition 中的方法时,需要提前获取到 Condition 关联的锁(Condition 对象是由 Lock 对象的 newCondition() 方法创建),也就是 Condition 依赖 Lock 对象。
1 public class ConditionUseCase {
2 Lock lock = new ReentrantLock();
3 Condition condition = lock.newCondition();
4 public void conditionWait() throws InterruptedException{
5 lock.lock();
6 try {
7 condition.await();
8 } finally {
9 lock.unlock();
10 }
11 }
12
13 public void conditionSignal() throws InterruptedException{
14 lock.lock();
15 try {
16 condition.signal();
17 } finally {
18 lock.unlock();
19 }
20 }
21 }

一般都会将 Condition 对象作为成员。当调用 await() 方法后,当前线程会释放锁并在此等待,而其他线程调用 Condition 对象的signal() 方法,通知当前线程后,当前线程才从 await() 方法返回,并且在返回前已经获取了锁。Condition 定义方法:
| 方法名称 | 描述 |
| void await() throws InterruptedException | 当前线程进入等待状态直到被通知(signal)或中断,当前线程将进入运行状态且从 await() 方法返回的情况,包括:其他线程调用该 Condition 的 signal()或signalAll()方法,或者被其他线程调用 interrupt 中断。如果当前线程从 await()方法返回,表明该线程已经获取了 Condition 对象所对应的锁。 |
| void awaitUninterruptibly() | 当前线程进入等待状态直到被通知,对中断不敏感。 |
| long awaitNanos(long nanosTimeout) throws InterruptedException | 当前线程进入等待状态直到被通知、中断或者超时。返回值表示剩余时间,如果在 nanosTimeout 纳秒之前被唤醒,那么返回值就是(nanosTimeout-实际消耗)返回值如果是0或者负数表示超时。 |
| boolean awaitUntil(Date deadline) throws InterruptedException | 当前线程进入等待状态直到被通知、中断或者到某个时间。如果没有到指定时间就被通知,方法返回true,否则,表示到了指定时间,方法返回 false。 |
| void signal() | 唤醒一个等待在 Condition 上的线程,该线程从等待方法返回前必须获得与Condition 相关的锁。 |
| void signalAll() | 唤醒所有等待在 Condition 上的线程,能够从等待方法返回的线程必须获得与Condition相关的锁。 |
二、Condition 的实现分析
ConditionObject 是同步器 AQS(AbstractQueuedSynchronize)的内部类,因为 Condition 的操作需要获取相关联的锁,所以作为同步器的内部类也比较合理。每个 Condition 对象都包含着一个队列(等待队列),该队列是 Condition 对象实现等待/通知功能的关键。
【1】等待队列:等待队列是一个 FIFO 的队列,队列中包含的是在 Condition 对象上等待的线程。如果一个线程调用 Condition.await() 方法,那么该线程就会释放锁、构造成节点加入到等待队列中。事实上,节点的定义复用了同步器中节点的定义,同步队列和等待队列中节点类型都是同步器的静态内部类 AbstractQueuedSynchronizer.Node。一个 Condition 包含一个等待队列,Condition 拥有首节点(firstWaiter)和尾结点(lastWaiter)。当前线程调用 Condition.await() 方法,将会以当前线程构造节点,并将节点从尾部加入等待队列。
【2】等待:调用 Condition 的 await() 方法(或者以 await 开头的方法),会使当前线程进入等待队列并释放锁,同时线程进入等待状态。如果不是通过调用 Condition.signal()方法唤醒,而是通过其他线程调用interrupt() 中断,则会抛出interruptedException 异常。
1 public final void await() throws InterruptedException {
2 if (Thread.interrupted())
3 throw new InterruptedException();
4 //当前线程构造成节点加入等待队列
5 Node node = addConditionWaiter();
6 //释放同步状态,也就是释放锁
7 int savedState = fullyRelease(node);
8 int interruptMode = 0;
9 while (!isOnSyncQueue(node)) {
10 LockSupport.park(this);
11 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
12 break;
13 }
14 if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
15 interruptMode = REINTERRUPT;
16 if (node.nextWaiter != null) // 取消时清除
17 unlinkCancelledWaiters();
18 if (interruptMode != 0)
19 reportInterruptAfterWait(interruptMode);
20 }
【3】通知:调用 Condition 的 signal() 方法,将会唤醒在等待队列中等待时间最长的节点(首节点),在唤醒之前,会将节点移到同步队列中。调用该方法的前提就是必须获取锁。signal 源码如下:通过调用同步器的 enq(Node node)方法,等待队列中的头节点线程安全移动到同步队列。当节点移动到同步队列后,当前线程再使用 LockSupport 的unpark唤醒该节点。
1 public final void signal() {
2 //isHeldExclusively 检查当前线程是否获取了锁
3 if (!isHeldExclusively())
4 throw new IllegalMonitorStateException();
5 //获取第一个Node
6 Node first = firstWaiter;
7 if (first != null)
8 doSignal(first);
9 }
被唤醒的线程,将从 await() 方法的 while 循环中退出(isOnSyncQueue(Node node))是否处于同步队列,方法返回 true 表示在同步队列,然后调用同步器的 acquireQueued() 方法加入到获取同步状态竞争中。被唤醒的线程将从调用的 await() 方法返回,此时该线程已经成功获取了锁。Condition的 signalAll() 方法,相当于对等待中的每一个节点执行了一次 signal() 方法,效果就是将等待队列中所有节点转移到同步队列 AQS 中,并唤醒每个节点的线程。
Condition 接口的更多相关文章
- 6.类似Object监视器方法的Condition接口
在<1.有关线程.并发的基本概念>中,我们利用synchronized关键字.Queue队列.以及Object监视器方法实现了生产者消费者,介绍了有关线程的一些基本概念.Object类提供 ...
- Java的LockSupport工具,Condition接口和ConditionObject
在之前我们文章(关于多线程编程基础和同步器),我们就接触到了LockSupport工具和Condition接口,之前使用LockSupport工具来唤醒阻塞的线程,使用Condition接口来实现线程 ...
- 并发之lock的condition接口
13.死磕Java并发-----J.U.C之Condition 12.Condition使用总结 11.Java并发编程系列之十七:Condition接口 === 13.死磕Java并发-----J. ...
- java中的锁之Lock接口与Condition接口
一.Lock源码. 1.是一个接口.一共有6个方法. 2.方法详细如下: (1)当前线程尝试获取锁.结果分两种情况,一是成功获取到锁,则返回:二是获取锁失败,则一直等待.不响应中断请求. (2)当前线 ...
- Condition接口
<Java并发编程艺术>读书笔记 Condition介绍 任意一个Java对象,都拥有一组监视器方法(定义在java.lang.Object中),主要包括wait().wait(long ...
- Java并发Condition接口
java.util.concurrent.locks.Condition接口提供一个线程挂起执行的能力,直到给定的条件为真. Condition对象必须绑定到Lock,并使用newCondition( ...
- Condition接口及其主要实现类ConditionObject源码浅析
1.引子 任意一个Java对象,都拥有一组监视器方法(定义在java.lang.Object上),主要包括wait().wait(long timeout).notify()以及notifyAll() ...
- Lock接口之Condition接口
之前在写显示锁的是后,在显示锁的接口中,提到了new Condition这个方法,这个方法会返回一个Condition对象 简单介绍一下 Condition接口: 任意一个Java对象,都拥有一组监视 ...
- Java 并发编程之 Condition 接口
本文部分摘自<Java 并发编程的艺术> 概述 任意一个 Java 对象,都拥有一个监视器方法,主要包括 wait().wait(long timeout).notify() 以及 not ...
- 精尽Spring Boot源码分析 - Condition 接口的扩展
该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...
随机推荐
- 什么是跨域及如何解决、json和jsonp
1.跨域: 出于浏览器的同源策略限制,同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互. 同源:即指在同一个域中,就是两个页面具有相同的协议(protocol),主机(host ...
- Cxf框架中@WebService注解的使用
最近工作中总是不可避免的使用WebService来对接功能,经过自己一番摸索,总结出了一些使用方法,做一下记录: 记录了两个SpringBoot版本使用WebService的一些问题和用法,Sprin ...
- nmap扫描
Nmap扫描 学习老师发的链接中的指令:https://www.cnblogs.com/nmap/p/6232207.html 下载了nmap软件 根据教学中的操作查找虚拟机的IP地址 并用主机对其扫 ...
- BZOJ1008 [HNOI2008]越狱 (快速幂,组合)
题目大意 求\(m\)种数字组成的长度为\(n\)的序列的种数,序列中至少有一段连续的数字 分析 用可重排列的种数减去,相邻数字互不相同的序列种数 考虑相邻互不相同,第一个元素有\(m\)种可能,后面 ...
- MySQL事务MVCC、undolog和redolog
MySql的MVCC多版本控制 undolog:回滚日志(保证一致性)只有在ReadCommited和RepeatableRead隔离级别有用 redolog:重写日志(保证持久性) 示例讲解 Rea ...
- Topsis法的python实现
TOPSIS (Technique for Order Preference by Similarity to an Ideal Solution )法是C.L.Hwang和K.Yoon于1981年首 ...
- curl 查看响应时间
curl -o /dev/null -s -w "time_namelookup:%{time_namelookup}\ntime_connect: %{time_connect}\ntim ...
- Navicat连接Mysql报错:Client does not support authentication protocol requested by server(转载)
Navicat连接MySQL Server8.0版本时出现Client does not support authentication protocol requested by server:解决 ...
- pandas(随时更新)
pandas处理一个表中的一列数据被另一个表中的另一列数据替换: df1=pd.DataFrame({'id':[1,2,3],'name':['Andy1','Jacky1','Bruce1']}) ...
- OSIDP-文件管理-12(end)
概述 文件特性:可长期存储:可在进程间共享:有特定结构. 文件系统提供对文件操作的功能接口:创建.删除.打开.关闭.读和写. 域(field):基本数据单元,一个域包含一个值. 记录(record): ...