一、Condition的概念

介绍

回忆 synchronized 关键字,它配合 Object 的 wait()、notify() 系列方法可以实现等待/通知模式。

对于 Lock,通过 Condition 也可以实现等待/通知模式。

Condition 是一个接口。

Condition 接口的实现类是 Lock(AQS)中的 ConditionObject。

Lock 接口中有个 newCondition() 方法,通过这个方法可以获得 Condition 对象(其实就是 ConditionObject)。

因此,通过 Lock 对象可以获得 Condition 对象。

Lock lock = new ReentrantLock();Condition c1 = lock.newCondition();Condition c2 = lock.newCondition();

二、Condition的实现分析

实现

ConditionObject 类是 AQS 的内部类,实现了 Condition 接口。

public class ConditionObject implements Condition, java.io.Serializable { private transient Node firstWaiter; private transient Node lastWaiter; ...

可以看到,等待队列和同步队列一样,使用的都是同步器 AQS 中的节点类 Node。

同样拥有首节点和尾节点,

每个 Condition 对象都包含着一个 FIFO 队列。

结构图:

Java并发之Condition的实现分析-1.jpg (9.01 KB, 下载次数: 0)

2020-6-7 22:32 上传

等待

调用 Condition 的 await() 方法会使线程进入等待队列,并释放锁,线程状态变为等待状态。

public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); //释放同步状态(锁) int savedState = fullyRelease(node); int interruptMode = 0; //判断节点是否放入同步对列 while (!isOnSyncQueue(node)) { //阻塞 LockSupport.park(this); //如果已经中断了,则退出 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode);}

分析上述方法的大概过程:

将当前线程创建为节点,加入等待队列;释放锁,唤醒同步队列中的后继节点;while循环判断节点是否放入同步队列:

没有放入,则阻塞,继续 while 循环(如果已经中断了,则退出)放入,则退出 while 循环,执行后面的判断退出 while 说明节点已经在同步队列中,调用 acquireQueued() 方法加入同步状态竞争。竞争到锁后从 await() 方法返回,即退出该方法。

Java并发之Condition的实现分析-2.jpg (30.35 KB, 下载次数: 0)

2020-6-7 22:32 上传

addConditionWaiter() 方法:

private Node addConditionWaiter() { Node t = lastWaiter; if (t != null && t.waitStatus != Node.CONDITION) { //清除条件队列中所有状态不为Condition的节点 unlinkCancelledWaiters(); t = lastWaiter; } //将该线程创建节点,放入等待队列 Node node = new Node(Thread.currentThread(), Node.CONDITION); if (t == null) firstWaiter = node; else t.nextWaiter = node; lastWaiter = node; return node;}

过程分析:同步队列的首节点移动到等待队列。加入尾节点之前会清除所有状态不为 Condition 的节点。

通知

调用 Condition 的 signal() 方法,可以唤醒等待队列的首节点(等待时间最长),唤醒之前会将该节点移动到同步队列中。

public final void signal() { //判断是否获取了锁 if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignal(first);}

过程:

先判断当前线程是否获取了锁;然后对首节点调用 doSignal() 方法。private void doSignal(Node first) { do { if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; } while (!transferForSignal(first) && (first = firstWaiter) != null);}

过程:

修改首节点;调用 transferForSignal() 方法将节点移动到同步队列。final boolean transferForSignal(Node node) { //将节点状态变为0  if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; //将该节点加入同步队列 Node p = enq(node); int ws = p.waitStatus; //如果结点p的状态为cancel 或者修改waitStatus失败,则直接唤醒 if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true;}

调用同步器的 enq 方法,将节点移动到同步队列,

满足条件后使用 LockSupport 唤醒该线程。

Java并发之Condition的实现分析-3.jpg (29.66 KB, 下载次数: 0)

2020-6-7 22:32 上传

当 Condition 调用 signalAll() 方法:

public final void signalAll() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignalAll(first);}private void doSignalAll(Node first) { lastWaiter = firstWaiter = null; do { Node next = first.nextWaiter; first.nextWaiter = null; transferForSignal(first); first = next; } while (first != null);}

可以看到 doSignalAll() 方法使用了 do-while 循环来唤醒每一个等待队列中的节点,直到 first 为 null 时,停止循环。

一句话总结 signalAll() 的作用:将等待队列中的全部节点移动到同步队列中,并唤醒每个节点的线程。

总结

整个过程可以分为三步:

第一步:一个线程获取锁后,通过调用 Condition 的 await() 方法,会将当前线程先加入到等待队列中,并释放锁。然后就在 await() 中的一个 while 循环中判断节点是否已经在同步队列,是则尝试获取锁,否则一直阻塞。

第二步:当线程调用 signal() 方法后,程序首先检查当前线程是否获取了锁,然后通过 doSignal(Node first) 方法将节点移动到同步队列,并唤醒节点中的线程。

第三步:被唤醒的线程,将从 await() 中的 while 循环中退出来,然后调用 acquireQueued() 方法竞争同步状态。竞争成功则退出 await() 方法,继续执行。

java并发condition_Java并发之Condition的实现分析相关推荐

  1. Java并发之Condition的实现分析

    2019独角兽企业重金招聘Python工程师标准>>> 一.Condition的概念 介绍 回忆 synchronized 关键字,它配合 Object 的 wait().notif ...

  2. 【多线程】java 并发编程中的Condition对象-指定唤醒某个线程

    1.概述 转载:java高并发系列 - 第13天:JUC中的Condition对象 synchronized中实现线程等待和唤醒 Condition简介及常用方法介绍及相关示例 使用Condition ...

  3. Java并发编程笔记之FutureTask源码分析

    FutureTask可用于异步获取执行结果或取消执行任务的场景.通过传入Runnable或者Callable的任务给FutureTask,直接调用其run方法或者放入线程池执行,之后可以在外部通过Fu ...

  4. Java 并发编程——Executor框架和线程池原理

    Java 并发编程系列文章 Java 并发基础--线程安全性 Java 并发编程--Callable+Future+FutureTask java 并发编程--Thread 源码重新学习 java并发 ...

  5. Java并发编程--ReentrantReadWriteLock

    概述 ReentrantReadWriteLock是Lock的另一种实现方式,我们已经知道了ReentrantLock是一个排他锁,同一时间只允许一个线程访问,而ReentrantReadWriteL ...

  6. Java并发编程—定时器Timer底层原理

    原文作者:妮蔻 原文地址:Java并发编程笔记之Timer源码分析 目录 一.timer问题复现 二.Timer 实现原理分析 timer在JDK里面,是很早的一个API了.具有延时的,并具有周期性的 ...

  7. java的condition_java并发编程之Condition

    引言 在java中,对于任意一个java对象,它都拥有一组定义在java.lang.Object上监视器方法,包括wait(),wait(long timeout),notify(),notifyAl ...

  8. 面试:你说你精通Java并发,给我讲讲Java并发之J.U.C

    转载自 面试:你说你精通Java并发,给我讲讲Java并发之J.U.C J.U.C J.U.C即java.util.concurrent包,为我们提供了很多高性能的并发类,可以说是java并发的核心. ...

  9. java 并发开发之AQS

    java 并发开发之AQS AQS 是什么,有什么作用? ① 是什么:AQS 是抽象队列同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖它 ② 有什么作用:为Java的并发 ...

最新文章

  1. 阿里全球数学竞赛第二届
  2. 通过ID在JavaScript对象数组中查找对象
  3. python编写爬虫的步骤-如何编写python脚本?教你做简单的爬虫,适合初学者
  4. 1.3编程基础之算术表达式与顺序执行 09 与圆相关的计算
  5. 一年中最后一个月的最后一天说说_一年最后一天的心情说说
  6. 心情有些复杂,不知道还能做多久,未来也不知道该如何选择
  7. 如何清除vsphere主机提示“此主机当前没有管理网络冗余”
  8. 思维导图是如何做会议记录的
  9. 计算机虚拟仿真专业,计算机虚拟仿真实验教学中心
  10. ⑤⭐全网首发☀️数据有道之数据库技术❤️干货大全【持续更新】❗❗❗
  11. 微信小程序下载文件并重命名,并在微信可以打开、保存并转发给好友
  12. JS 对象直接量方法创建对象
  13. 资深程序猿冒死揭开软件潜规则:无法维护的代码
  14. 江苏大专计算机考试,江苏省教育考试院2020年高职(专科)注册入学申请入口...
  15. IOS HTTPS 服务器信任评估
  16. 纵断面 java_道路土方计算软件
  17. 中国二次锂离子电池电解液市场需求现状与销售策略分析报告2022-2028年
  18. linux中使用jmeter压测
  19. AMD公司2020财年第三季度收益电话会议
  20. 06-数据科学的基础:数据收集之市场调查_02 次级资料

热门文章

  1. c语言中数据存储在文件中,急求如何将下列C语言程序数据存储到文件中?
  2. seata 如何开启tcc事物_分布式事务Seata-TCC源码分析
  3. 名图1.8智能隐藏功能_7年后再度回归 全新一代名图“大”不同_搜狐汽车
  4. 学python开发必须要会wsgi么_python Web开发你要理解的WSGI uwsgi详解
  5. 正态分布的前世今生(3)
  6. 【生活科普】这7个影视剧的经典桥段,骗了我们很多年……
  7. 基于随机森林的分类与回归
  8. centos6 yum安装mysql5.6_centos 6.5 yum安装mysql 5.6
  9. WordPress架构简单剖析
  10. 二叉树学习之二叉查找树