JUC.Condition学习
目录
I.初始化状态 II.await()操作 III.signal()操作
Condition的数据结构
线程何时阻塞和释放
await()方法
signal()和signalAll()方法
JUC提供了Lock可以方便的进行锁操作,但是有时候我们也需要对线程进行条件性的阻塞和唤醒,这时我们就需要condition条件变量,它就像是在线程上加了多个开关,可以方便的对持有锁的线程进行阻塞和唤醒。
Condition的概念
Condition实质上是被绑定到一个锁上。
大体实现流程


3个主要方法
Condition的数据结构
线程何时阻塞和释放
await方法
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public final void await() throws InterruptedException {
// 1.如果当前线程被中断,则抛出中断异常 if (Thread.interrupted()) throw new InterruptedException(); // 2.将节点加入到Condition队列中去,这里如果lastWaiter是cancel状态,那么会把它踢出Condition队列。 Node node = addConditionWaiter(); // 3.调用tryRelease,释放当前线程的锁 long savedState = fullyRelease(node); int interruptMode = 0; // 4.为什么会有在AQS的等待队列的判断? // 解答:signal操作会将Node从Condition队列中拿出并且放入到等待队列中去,在不在AQS等待队列就看signal是否执行了 // 如果不在AQS等待队列中,就park当前线程,如果在,就退出循环,这个时候如果被中断,那么就退出循环 while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } // 5.这个时候线程已经被signal()或者signalAll()操作给唤醒了,退出了4中的while循环 // 自旋等待尝试再次获取锁,调用acquireQueued方法 if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); } |
signal和signalAll方法
await*()清楚了,现在再来看signal/signalAll就容易多了。按照signal/signalAll的需求,就是要将Condition.await*()中FIFO队列中第一个Node唤醒(或者全部Node)唤醒。尽管所有Node可能都被唤醒,但是要知道的是仍然只有一个线程能够拿到锁,其它没有拿到锁的线程仍然需要自旋等待,就上上面提到的第4步(acquireQueued)。
|
1
2 3 4 5 6 7 |
public final void signal() {
if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignal(first); } |
这里先判断当前线程是否持有锁,如果没有持有,则抛出异常,然后判断整个condition队列是否为空,不为空则调用doSignal方法来唤醒线程,看看doSignal方法都干了一些什么:
|
1
2 3 4 5 6 7 8 |
private void doSignal(Node first) {
do { if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; } while (!transferForSignal(first) && (first = firstWaiter) != null); } |
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
final boolean transferForSignal(Node node) {
/* * 设置node的waitStatus:Condition->0 */ if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; /* |
|
1
2 3 4 5 6 7 8 9 |
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null; do { Node next = first.nextWaiter; first.nextWaiter = null; transferForSignal(first); first = next; } while (first != null); } |
这个方法就相当于把Condition队列中的所有Node全部取出插入到等待队列中去。
Condition应用示例:生产者和消费者
Condition 实例实质上被绑定到一个锁上。要为特定 Lock 实例获得 Condition 实例,请使用其 newCondition() 方法。在最后我们来看一个应用示例
|
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
/**
* 生产者、消费者示例 */ public class ConditionTest { private int storage; private int putCounter; private int getCounter; private Lock lock = new ReentrantLock(); private Condition putCondition = lock.newCondition(); private Condition getCondition = lock.newCondition(); public void put() throws InterruptedException { public void get() throws InterruptedException { public class PutThread extends Thread { public class GetThread extends Thread { public static void main(String[] args) { |
JUC.Condition学习的更多相关文章
- JUC.Condition学习笔记[附详细源码解析]
目录 Condition的概念 大体实现流程 I.初始化状态 II.await()操作 III.signal()操作 3个主要方法 Condition的数据结构 线程何时阻塞和释放 await()方法 ...
- JUC——检视阅读
JUC--检视阅读 参考资料 JUC知识图参考 JUC框架学习顺序参考 J.U.C学习总结参考,简洁直观 易百并发编程,实践操作1,不推荐阅读,不及格 JUC文章,带例子讲解,可以学习2 Doug L ...
- JUC之线程间的通信
线程通信 视频1: 2021.12.18 JUC视频学习片段 对上次多线程编程步骤补充(中部): 创建资源类,在资源类中创建属性和操作方法 在资源类里面操作 判断 干活 通知 创建多个线程,调用资源类 ...
- Condition线程通信(七)
前言:对于线程通信,使用synchronized时使用wait.notify和notifyAll来实行线程通信.而使用Lock如何处理线程通信呢?答案就是本片的主角:Condition. 一.Cond ...
- 你知道什么是JUC了吗?
多线程一直Java开发中的难点,也是面试中的常客,趁着还有时间,打算巩固一下JUC方面知识,我想机会随处可见,但始终都是留给有准备的人的,希望我们都能加油!!! 沉下去,再浮上来,我想我们会变的不一样 ...
- day-4 python多进程编程知识点汇总
1. python多进程简介 由于Python设计的限制(我说的是咱们常用的CPython).最多只能用满1个CPU核心.Python提供了非常好用的多进程包multiprocessing,他提供了一 ...
- 我们一起来回顾一下Synchronized关键字吧
多线程一直Java开发中的难点,也是面试中的常客,趁着还有时间,打算巩固一下JUC方面知识,我想机会随处可见,但始终都是留给有准备的人的,希望我们都能加油!!! 沉下去,再浮上来,我想我们会变的不一样 ...
- 学习JUC源码(3)——Condition等待队列(源码分析结合图文理解)
前言 在Java多线程中的wait/notify通信模式结尾就已经介绍过,Java线程之间有两种种等待/通知模式,在那篇博文中是利用Object监视器的方法(wait(),notify().notif ...
- JUC.Lock(锁机制)学习笔记[附详细源码解析]
锁机制学习笔记 目录: CAS的意义 锁的一些基本原理 ReentrantLock的相关代码结构 两个重要的状态 I.AQS的state(int类型,32位) II.Node的waitStatus 获 ...
随机推荐
- .net mvc mssql easyui treegrid
效果图 数据图 可以看到 这里是根据 MenuNo 来 分级别的,支持 无限极,第一级是 01 ,第二级就是 01XX ,第三级 就是 01XXOO.类似 id.pid ,Ztree 里面 也是这 ...
- 我的MYSQL学习心得(八)
原文:我的MYSQL学习心得(八) 我的MYSQL学习心得(八) 我的MYSQL学习心得(一) 我的MYSQL学习心得(二) 我的MYSQL学习心得(三) 我的MYSQL学习心得(四) 我的MYSQL ...
- Factorization Machines 学习笔记(二)模型方程
近期学习了一种叫做 Factorization Machines(简称 FM)的算法,它可对随意的实值向量进行预測.其主要长处包含: 1) 可用于高度稀疏数据场景:2) 具有线性的计算复杂度.本文 ...
- JS代码的几个注意点规范
也谈谈规范JS代码的几个注意点 也谈谈规范JS代码的几个注意点 写JS代码差不多也有两年了吧,从刚开始的“初生牛犊不怕虎”乱写一通到后来也慢慢知道去规范一下自己写的代码.这种感觉就像是代码是你的作品, ...
- 深入理解JavaScript(1)
才华横溢的Stoyan Stefanov,在他写的由O’Reilly初版的新书<JavaScript Patterns>(JavaScript模式)中,我想要是为我们的读者贡献其摘要,那会 ...
- SQL点滴3—一个简单的字符串分割函数
原文:SQL点滴3-一个简单的字符串分割函数 偶然在电脑里看到以前保存的这个函数,是将一个单独字符串切分成一组字符串,这里分隔符是英文逗号“,” 遇到其他情况只要稍加修改就好了 CREATE FUN ...
- PDF解决方案(4)--在线浏览
相关专题链接 PDF解决方案(1)--文件上传 PDF解决方案(2)--文件转PDF PDF解决方案(3)--PDF转SWF PDF解决方案(4)--在线浏览 前言:上一篇主要提到了PDF在线浏览的各 ...
- 系统预定义委托与Lambda表达式
NET中那些所谓的新语法之三:系统预定义委托与Lambda表达式 开篇:在上一篇中,我们了解了匿名类.匿名方法与扩展方法等所谓的新语法,这一篇我们继续征程,看看系统预定义委托(Action/Fun ...
- 使用Clean() 去掉由函数自动生成的字符串中的双引号
有时候由Excel单元格函数軿凑出来的字符串会自带双引号 效果如下: 想这种这个情况,刚好我们軿凑出来的是SQL语句, 执行的时候是去掉双引号, 这时候可以使用Excel自带的函数来去掉双引号 Cle ...
- 通过SqlClr制作Sql自动化批量执行脚本
原文:通过SqlClr制作Sql自动化批量执行脚本 通过SqlClr制作Sql自动化批量执行脚本 在与同事一起做项目时,看到同事用sqlclr做批量执行脚本,感觉挺新奇的就上网搜集资料自己模仿跟做了个 ...
