我们知道,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源码解析相关推荐

  1. 多线程与高并发(八):ThreadPoolExecutor源码解析, SingleThreadPool,CachedPool,FixedThreadPool,ForkJoinPoll 等

    线程池 今天我们来看看JDK给我们提供的默认的线程池的实现. ThreadPoolExecutor:我们通常所说的线程池.多个线程共享同一个任务队列. SingleThreadPool CachedP ...

  2. java treeset原理_Java集合 --- TreeSet底层实现和原理(源码解析)

    概述 文章的内容基于JDK1.7进行分析,之所以选用这个版本,是因为1.8的有些类做了改动,增加了阅读的难度,虽然是1.7,但是对于1.8做了重大改动的内容,文章也会进行说明. TreeSet实现了S ...

  3. Java生鲜电商平台-促销系统的架构设计与源码解析

    Java生鲜电商平台-促销系统的架构设计与源码解析 说明:本文重点讲解现在流行的促销方案以及源码解析,让大家对促销,纳新有一个深入的了解与学习过程. 促销系统是电商系统另外一个比较大,也是比较复杂的系 ...

  4. Java生鲜电商平台-商品中心的架构设计与源码解析(小程序/APP)

    Java生鲜电商平台-商品中心的架构设计与源码解析(小程序/APP) 说明:Java生鲜电商平台中,由于商品的架构很大程度决定了电商的扩展性与伸缩性.对此根据自己多年的生鲜电商经验,整理了以下的商品中 ...

  5. shell 获取命令执行结果_java高并发系列 第31天:获取线程执行结果,这6种方法你都知道?...

    这是java高并发系列第31篇. 环境:jdk1.8. java高并发系列已经学了不少东西了,本篇文章,我们用前面学的知识来实现一个需求: 在一个线程中需要获取其他线程的执行结果,能想到几种方式?各有 ...

  6. Java 并发编程Semaphore的应用与源码解析

    What Semaphore标识信号量,允许指定数量的线程同时访问某个资源 How 通过以下两部实现信号量: acquire方法用于获得准入许可(如果没有获得许可,则进行等待,直到有线程释放许可而获得 ...

  7. Java 并发编程CyclicBarrier的应用与源码解析(基于ReentrantLock实现)

    什么是CyclicBarrier? CyclicBarrie和上一篇中讲到CountDownLatch很类似,它能阻塞一组线程直到某个事件的发生. 栅栏与闭锁的关键区别在于:所有必须同时到达栅栏位置才 ...

  8. Java 并发编程CountDownLatch的应用与源码解析

    应用场景 CountDownLatch是一个多线程控制工具.用来控制线程的等待. 设置需要countDown的数量,然后每一个线程执行完毕后调用countDown()方法,而在主线程中调用await( ...

  9. java 检视_Java高并发系列——检视阅读(五)

    JUC中工具类CompletableFuture CompletableFuture是java8中新增的一个类,算是对Future的一种增强,用起来很方便,也是会经常用到的一个工具类,熟悉一下. Co ...

最新文章

  1. 微软Cortana全面升级神经网络语音,效果堪比真人发音
  2. css清除浮动的几种方法_web前端学习路线分享CSS浮动-清除浮动篇
  3. Swagger2 @ApiImplicitParam中dataType和paramType的区别?
  4. DVWA-SQL注入
  5. mysql基本表管理sql语句
  6. 2018年1月问答系统综述
  7. 关键字:auto、static、register、const、volatile 、extern 总结
  8. FoneDog Toolkit iOS Data Recovery如何从iPhone恢复已删除的数据
  9. 产生随机数(rand()函数和srand()函数)的含义
  10. Java——删除文件
  11. WEB前端优化必备压缩工具YUI-compressor详解
  12. 我的Java学习历程03【Java8接口新特性-下】
  13. 命令行基础-tar命令详解
  14. 计算机应用研究参考文献格式,参考文献编写规则-计算机应用研究.PDF
  15. 搭建 IPv6 Web服务器
  16. 记录ESP32 出现未定义vTaskGetRunTimeStats的奔溃时刻!
  17. 西雅图又一家科技公司准备上市!
  18. 单目视觉标定(1)原理解析
  19. matlab伽玛函数,[MATLAB数学相关] 求助!类似伽玛函数 带参变量广义积分 积分结果是求极限...
  20. 比尔总动员》座驾改装材料收集攻略

热门文章

  1. 源代码方式和二进制包的区别
  2. 十行代码,用Python做一个迷你版的美图秀秀
  3. 如何用社群引流裂变?社群裂变引流怎么操作?
  4. 【深度学习前沿应用】图像风格迁移
  5. Bluestacks蓝叠安卓模拟器与PC电脑怎么传文件
  6. 对日方向的程序员怎么快速学习日语
  7. 一文掌握SOP知识精华及编写步骤方法
  8. Flink checkpoint失败
  9. 我的win7 64 激活过了,但是计算机-属性仍然显示“未激活此WIndows副本,单击此处立即激活...
  10. SPSS分析MySQL数据库数据出现中文乱码问题