java中acquire()_Java高并发系列之AQS中acquire源码解析
我们知道,AQS中最重要的两个方法就是acquire和release方法。我们本文来走读走读acquire的源码。
首先,tryAcquire是需要子类具体去实现,其作用就是设置state的值,如果设置成功,就代表获取资源,否则会进入下面的流程,也就是将当前线程封装到阻塞队列。
下面先来分析addWaiter方法。我们进入addWaiter方法看看。
1、首先,创建一个Node节点,我们知道这个Node节点是AQS的一个内部类。也是AQS阻塞队列(注:AQS阻塞队列是基于双向链表实现的)的基本类型,你可以想象成链表的Node节点。
2、由于AQS插入的顺序是在尾节点tail插入元素,取元素是在head节点进行。AQS初始化的时候,head和tail都指向null。因此这里Node pred首先指向尾节点。如果尾节点不为空则将当前创建的node节点前驱节点设置为pred。然后调用compareAndSetTail这个CAS操作将当前创建的node设置为tail节点,如果设置成功则将之前尾节点的pred后驱节点指向node。这里也就是说将新创建的node设置为新的tail节点,同时设置链表的指针。
3、如果尾节点为null,那么就会进入enq方法,这个方法就是AQS入队操作,其实也就是双向链表的操作,具体可以字节去看看源码。
下面来来看看acquireQueued()方法的源码。
1、进入死循环。先获取 node 对象 prev 节点,如果该节点和 head 相等,说明是他的第二个节点,那么此时就可以尝试获取锁了。 如果获取锁成功,就设置当前节点为 head 节点(同时设置当前node的线程为null,prev为null),并设置他的 prev 节点的 next 节点为 null(帮助GC回收)。最后,返回等待过程中是否中断的布尔值。
2、如果上面的两个条件不成立,则调用shouldParkAfterFailedAcquire方法和parkAndCheckInterrupt 方法。这两个方法的目的就是将当前线程挂起。然后等待被唤醒或者被中断。稍后,我们仔细查看这两个方法。
3、如果挂起后被当前线程唤醒,则再度循环,判断是该节点的 prev 节点是否是 head。一般来讲,当线程被唤醒,说明你可以获取锁了,也就是 head 节点完成了任务释放了锁。然后重复步骤 1。最后返回。
我们来看看shouldParkAfterFailedAcquire方法的源码。
这个代码比较简单,首先我们先看一下Node节点中定义的几种状态。
现在再来看shouldParkAfterFailedAcquire的源码。
1、获取去上一个节点的等待状态,如果状态是 SIGNAL,就直接返回 true,表示可以挂起并休息。
2、如果 waitStatus 大于 0, 则循环检查 prev 节点的 prev 的waitStatus,直到遇到一个状态不大于0。该字段有4个状态,分别是 CANCELLED = 1,SIGNAL = -1, CONDITION = -2, PROPAGATE = -3,也就是说,如果大于 0,就是取消状态。那么,往上找到那个不大于0的节点后怎么办?将当前节点指向那个节点的 next 节点,也就是说,那些大于0 状态的节点都失效这里,随时会被GC回收。
3、如果不大于0 也不是 -1,则将上一个节点的状态设置为有效, 也就是将Node的状态设置为SIGNAL。
下面,我们再看看parkAndCheckInterrupt方法的源码。
该方法非常的简单,就是将当前线程挂起,等到有别的线程唤醒(通常是 head 节点的线程),然后返回当前线程是否是被中断了,注意,该方法会清除中断状态。
总结:
AQS中的acquire的源码其实还是比较简单的,读者可以对着源码再详细过一遍加深理解和印象。
java中acquire()_Java高并发系列之AQS中acquire源码解析相关推荐
- 多线程与高并发(八):ThreadPoolExecutor源码解析, SingleThreadPool,CachedPool,FixedThreadPool,ForkJoinPoll 等
线程池 今天我们来看看JDK给我们提供的默认的线程池的实现. ThreadPoolExecutor:我们通常所说的线程池.多个线程共享同一个任务队列. SingleThreadPool CachedP ...
- java treeset原理_Java集合 --- TreeSet底层实现和原理(源码解析)
概述 文章的内容基于JDK1.7进行分析,之所以选用这个版本,是因为1.8的有些类做了改动,增加了阅读的难度,虽然是1.7,但是对于1.8做了重大改动的内容,文章也会进行说明. TreeSet实现了S ...
- Java生鲜电商平台-促销系统的架构设计与源码解析
Java生鲜电商平台-促销系统的架构设计与源码解析 说明:本文重点讲解现在流行的促销方案以及源码解析,让大家对促销,纳新有一个深入的了解与学习过程. 促销系统是电商系统另外一个比较大,也是比较复杂的系 ...
- Java生鲜电商平台-商品中心的架构设计与源码解析(小程序/APP)
Java生鲜电商平台-商品中心的架构设计与源码解析(小程序/APP) 说明:Java生鲜电商平台中,由于商品的架构很大程度决定了电商的扩展性与伸缩性.对此根据自己多年的生鲜电商经验,整理了以下的商品中 ...
- shell 获取命令执行结果_java高并发系列 第31天:获取线程执行结果,这6种方法你都知道?...
这是java高并发系列第31篇. 环境:jdk1.8. java高并发系列已经学了不少东西了,本篇文章,我们用前面学的知识来实现一个需求: 在一个线程中需要获取其他线程的执行结果,能想到几种方式?各有 ...
- Java 并发编程Semaphore的应用与源码解析
What Semaphore标识信号量,允许指定数量的线程同时访问某个资源 How 通过以下两部实现信号量: acquire方法用于获得准入许可(如果没有获得许可,则进行等待,直到有线程释放许可而获得 ...
- Java 并发编程CyclicBarrier的应用与源码解析(基于ReentrantLock实现)
什么是CyclicBarrier? CyclicBarrie和上一篇中讲到CountDownLatch很类似,它能阻塞一组线程直到某个事件的发生. 栅栏与闭锁的关键区别在于:所有必须同时到达栅栏位置才 ...
- Java 并发编程CountDownLatch的应用与源码解析
应用场景 CountDownLatch是一个多线程控制工具.用来控制线程的等待. 设置需要countDown的数量,然后每一个线程执行完毕后调用countDown()方法,而在主线程中调用await( ...
- java 检视_Java高并发系列——检视阅读(五)
JUC中工具类CompletableFuture CompletableFuture是java8中新增的一个类,算是对Future的一种增强,用起来很方便,也是会经常用到的一个工具类,熟悉一下. Co ...
最新文章
- 微软Cortana全面升级神经网络语音,效果堪比真人发音
- css清除浮动的几种方法_web前端学习路线分享CSS浮动-清除浮动篇
- Swagger2 @ApiImplicitParam中dataType和paramType的区别?
- DVWA-SQL注入
- mysql基本表管理sql语句
- 2018年1月问答系统综述
- 关键字:auto、static、register、const、volatile 、extern 总结
- FoneDog Toolkit iOS Data Recovery如何从iPhone恢复已删除的数据
- 产生随机数(rand()函数和srand()函数)的含义
- Java——删除文件
- WEB前端优化必备压缩工具YUI-compressor详解
- 我的Java学习历程03【Java8接口新特性-下】
- 命令行基础-tar命令详解
- 计算机应用研究参考文献格式,参考文献编写规则-计算机应用研究.PDF
- 搭建 IPv6 Web服务器
- 记录ESP32 出现未定义vTaskGetRunTimeStats的奔溃时刻!
- 西雅图又一家科技公司准备上市!
- 单目视觉标定(1)原理解析
- matlab伽玛函数,[MATLAB数学相关] 求助!类似伽玛函数 带参变量广义积分 积分结果是求极限...
- 比尔总动员》座驾改装材料收集攻略