AQS作为JUC并发组件实现的核心。全称是AbstructQueuedSynchronizer,也就是同步队列器。

其内部实现主要的是一个state状态标识和基于FIFO一个同步队列

这个状态标识表明当前的资源是否是可以争取的,当state=0是,表示资源没有加锁;当state>0时,表示资源加锁。

关于这个队列,有几个属性:

1)队列是基于双向链表的,因此具有定制的节点结构信息。node

2)tail尾指针,指向队列的最后一个节点

3)头指针,指向队列的第一个节点(也即是   头节点)。头结点中包含有当前资源的同步状态信息。

4)waitStatus 节点等待标识。

=1时   SIGNAL   表明当前节点的后继节点所包含的线程需要运行。

=-1    CANCEL  表明当前节点线程取消

=-2    CONDITION 表明当前节点在等待condition  处于Condition等待队列

=-3    PROPAGATE  应用在共享锁中

= 0   当前节点在同步队列中,等待获取锁


AQS是通过内部的同步队列来完成线程获取资源的排队工作

AQS可以实现独占锁和共享锁。

ReentrantLock实现的是独占锁;ReentrantReadWriteLock实现的是独占锁和共享锁;CountDownLatch实现的是共享锁。

因此,关于锁的获取和释放有以下几种方式:

1)独占式获取锁

首先,线程尝试获得锁tryAcquire,获取成功则函数返回,获得失败,addWaiter构造一个独占模式同步节点,如果前驱节点不为空则将该节点采用CAS方式放置到同步队列尾部,如果放置失败则说明当前节点位置存在并发竞争,进入enq方法进行添加,其实,enq方法也就是通过CAS自旋锁的方式不断地尝试来向队列中添加构造的节点;

如果节点最后成功地放置到队列里。执行acquireQueued方法,当前节点中的线程通过自旋方式尝试获取同步状态。

如果当前节点的前驱节点是头结点,并且重新尝试获取锁成功,就将当前节点设置为头结点!否则判断当前线程是否可以被安全阻塞挂起(根据waitStatus来判断,判断函数shouldParkAfterFailedAcquire),是的话就调用parkAndCheckInterrupt方法里的park方法进行挂起。然后再次进入for循环自旋。

如何判断????

当前节点的前驱节点是waitStatus是SIGNAL则可以挂起,之后由前驱节点进行唤醒;

若前驱节点是CANCEL 则向前遍历直到找到一个是SIGNAL的节点,并将当前节点放置在此节点的后面,不能挂起;

否则尝试将前驱节点的状态设置为SIGNAL,不能挂起

2)独占式释放锁

调用release方法来释放锁。这个方法一般由子类自己重写。

首先,尝试释放tryRelease,如果成功那么就唤醒后继节点    unparkSuccessor里的LockSupport.unpark方法

3)共享式获得锁

调用acquireShared方法,首先尝试获得锁,获得成功就返回;获得失败进入等待队列。直到获取到资源为止才返回。

若当前节点的前驱节点是头结点,则尝试进行加锁;如果加锁成功就调用setHeadAndPropagate,将当前节点设置为头结点,唤醒后继节点,并将之前的头结点从队列中踢出去,等待GC回收;

shared模式下是允许多个线程持有一把锁的,其中tryAcquire的返回值标志了是否允许其他线程继续进入。如果允许的话,需要唤醒队列中等待的线程。其中setHeadAndPropagate方法中的doReleaseShared方法的逻辑很简单,就是唤醒后继线程。

如果获得锁失败,判断当前线程是否可以被安全阻塞挂起,是的话就调用parkAndCheckInterrupt方法里的park方法进行挂起。

tryAcquireShared返回值为正,说明获得锁成功,负数则失败。

4)共享式释放锁

调用releaseShared方法;尝试释放锁,释放成功再次调用doReleaseShared,此方法内部还是调用LockSupport.unpark()方法唤醒后继线程。

5)独占超时获得锁

相比于独占获得锁方式,最重要的区别就是:独占获得锁在自旋获得锁失败之后会挂起,让出CPU时间片,之后再次进入for循环自旋尝试获得锁;而独占超时获得锁在获得锁失败之后,判断当前时间是否超时?若超时,则直接返回不再进行for循环;若没有超时,则将当前线程阻塞指定的超时时间之后再次进行for循环进行CAS自旋获取锁!

调用doAcquireNanos方法。该方法在自旋过程中,当节点的前驱节点为头节点时尝试获取同步状态,如果获取成功则从该方法返回,这个过程和独占式同步获取的过程类似,

但是在同步状态获取失败的处理上有所不同。如果当前线程获取同步状态失败,则首先重新计算超时间隔nanosTimeout,则判断是否超时(nanosTimeout小于等于0表示已经超时),如果没有超时,则使当前线程等待nanosTimeout纳秒(当已到设置的超时时间,该线程会从LockSupport.parkNanos(Object blocker,long nanos)方法返回)。

如果nanosTimeout小于等于spinForTimeoutThreshold(1000纳秒)时,将不会使该线程进行超时等待,而是进入快速的自旋过程。原因在于,非常短的超时等待无法做到十分精确,如果这时再进行超时等待,相反会让nanosTimeout的超时从整体上表现得反而不精确。因此,在超时非常短的场景下,同步器会进入无条件的快速自旋。

详情请参见本博客多线程模块AQS源码分析文章

多线程:AQS的一些心得相关推荐

  1. Java多线程 - AQS详解

    介绍 AQS是java.util.concurrent.locks下类AbstractQueuedSynchronizer的简称,是用于 通过Java源码来构建多线程的锁和同步器的一系列框架,用于Ja ...

  2. 多线程—AQS独占锁与共享锁原理

    java.util.concurrent.locks包下,包含了多种锁,ReentrantLock独占锁.ReentrantReadWriteLock读写锁等,还有java.util.concurre ...

  3. Java 多线程 —— AQS 详解

    引言 AQS 是AbstractQuenedSynchronizer 的缩写,抽象的队列式同步器,它是除了java自带的synchronized关键字之外的锁机制.是 JUC 下的重要组件. 相关产物 ...

  4. java多线程aqs实现工具类_Java并发多线程 - 并发工具类JUC

    (adsbygoogle = window.adsbygoogle || []).push({}); 安全共享对象策略 1.线程限制 : 一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改 ...

  5. linux c 多线程socket编程,Linux多线程socket编程一些心得

    前段时间将新的web模型办到Linux上来,用epoll代替了IOCP,经测试确实性能提高了很多,吞吐量也寓所提高,对于Linux下面的网络编程不是三言两语就能说得透的了,加上多线程就更麻烦了,但是e ...

  6. Java 多线程 —— AQS 原理

    引言 使用Condition实现生产者-消费者模型,并与wait和notify实现的效果相对比. wait/notify模拟生产者-消费者 面试题:写一个固定容量同步容器,拥有put和get方法,以及 ...

  7. python多线程填写体温(一次可填写10+位+含双验证码填写)----升级至尊版

    继上次教程:利用python制作自动填写体温程序最详细教程来了(有后续哦) {注意:代码已经无法运行,仅做参考} 需要完整代码的同学看目录自取,也可以加强学习,大家一起学习交流呀! 温馨提示:本代码仅 ...

  8. JAVA后端面经总结

    JAVA后端开发知识总结(持续更新-) JAVA后端面经总结 文章目录 JAVA后端面经总结 一.JAVA基础 一.1.设计模式 二.MySQL 三.多线程 五.Redis 六(1).计算机网络 六( ...

  9. 尚硅谷Java第三季--1.javaj基础

    1. javaj基础 Java字符串常量池 public class StringPools58Demo {public static void main(String[] args) {/*(1). ...

最新文章

  1. c++后台开发项目_[c/c++后台开发面经系列]4 Zoom面经(含答案)
  2. 打开word或者office程序报错:Microsoft Visual C++ Runtime Library. Runtime Error!
  3. PHP 5.6.32 增加pdo_dblib.so拓展
  4. 获取程序代码块资源消耗
  5. Java泛型总结--转
  6. 极大似然估计的朴素理解
  7. Vue+Openlayers+el-checkbox实现多选配置图层的显示和隐藏
  8. oauth2 access_denied 不允许访问_OAuth 2 是什么-入门介绍
  9. 架构设计中的方法学(七)
  10. 全栈工程师薪水_2020 Java 全栈工程师进阶路线图,不可错过
  11. Typecho安装后后台界面和文章链接均为404错误的解决方法
  12. STL的Vector介绍
  13. 基于mpvue的toast组件
  14. stochastic noise and deterministic noise
  15. 记录-如何测试服务器是否支持ipv6
  16. C++ vector 和push_back 详解
  17. 其实,我对你是有一些失望的。
  18. 制图操作案例:在Pro画水墨画
  19. 基于独立工作流引擎实现的SuperFlow工作流平台设计方案
  20. nginx 配置优化的几个参数

热门文章

  1. 如何在Hadoop上运行TensorFlow【部署】
  2. SQL Server调优系列基础篇(子查询运算总结)
  3. 牛客网在线编程之“字符串分割”
  4. IGBT的MATLAB仿真
  5. 基于matlab的点云重建与三角剖分
  6. 基于双向链表的增删改查和排序(C++实现)
  7. 论文笔记:Spherical CNN
  8. oracle 行送,Oracle 行专列
  9. 运算服务器v9型号,v9云服务器
  10. 返回1到n的所有组合python_如何在Python中生成0-1矩阵的所有可能组合?