在上一次总结中,提到了JUC包下使用Lock接口实现同步的方法,以及和Synchronized关键字的一些比较,那么使用Lock完成锁机制的底层支持又是什么呢?总结如下:

1 AQS是什么

AQS是一个抽象类,全名AbstractQueuedSynchronizer,意为抽象的队列式同步器。他在整个同步机制的作用如下:

AQS是一个中间的工具类,它的基础是CAS操作,和volatile关键字的支持。最终还是给Lock接口下的类提供服务的,具体包括获取对象锁的方法、将获取锁失败线程挂挂到等待队列、维护队列等等

2 AQS是如何与Lock合作的

在上次总结以及给出AQS与Lock接口下的实现类的关系,这次更详细的总结一下:

在创建ReentrantLock时可以指定公平or不公平锁,非公平锁,即对于同一个锁,不保证先到的线程会首先获得。以非公平锁为例,Lock接口下的ReentrantLock类持有一个AQS抽象类下的实现类NofairSync类,ReentrantLock又是由一个对象持有,我们可以简单的认为一个对象持有一个AQS类实例,这个AQS类实例有一个成员变量state(int)则是关键之关键。

state变量代表所属对象的状态,state == 0 则说明所属对象还没有被线程获取到锁,否则说明以及有线程已经获取到锁正在访问同步块。线程通过Lock机制获取锁的过程其实就是修改对象的state变量的过程,这个修改过程正是由CAS操作完成的,所以state也需要由volatile关键字修饰,保证state变量的可见性,即CAS操作时变量值是最新的。

        说白了,Synchronized机制下通过对象头的几个标志位的值来表示对象的锁状态。而Lock机制下则通过让对象持有AQS的state变量,用state变量的值表示对象的锁状态。

当然除了state还有其他变量,如调用nofairTryAcquire(acquires)中,acquires表示锁被请求的次数 。当state == 0则CAS修改acquires为1,每次重入+1,unlock则-1;当state != 0 ,且发现线程已经获得了锁,则直接acquires+1,实现重入锁的功能。

获取锁的代码和过程很复杂,这里只是从最顶层的角度描述大致过程,很多细节需要大量篇幅叙述。想了解的可以看看源码。

3 获取锁失败线程怎么办

如果发现state != 0,或者 state == 0  CAS修改失败,则表明获取锁失败。这个时候,就会调用AQS下的 addWaiter(Node n)将失败的线程包成一个节点,用CAS的方法插入一个CLH(基于链表的、公平的自旋锁)的双向队列的尾部,tail节点之后成为新的tail节点。  若CAS插入失败,则调用enq(Node n)再次使用CAS尝试重新插入。

对于新进入队列的节点,不会立即将它阻塞,而是再次尝试获取锁,若还是失败则调用lockSupport.park () ,在这个方法中调用 sun.misc.unsafe.park()Native方法,通过系统内核阻塞它。

(图片来源于网络)

队列的节点都有一个状态位,该状态位与线程状态密切相关:

CANCELLED =  1:因为超时或者中断,节点会被设置为取消状态,被取消的节点时不会参与到竞争中的,他会一直保持取消状态不会转变为其他状态;

SIGNAL    = -1:其后继节点已经被阻塞了,到时需要进行唤醒操作;

CONDITION = -2:表示这个结点在条件队列中,因为等待某个条件而被阻塞;

0:新建节点一般都为0。

AQS这里很复杂,这里只是从最顶层的角度做了一些粗浅的总结,并不深入。

JUC包Lock机制的支持--AQS的更多相关文章

  1. JUC包实现的同步机制,原理以及简单用法总结

    除了用Synchronized关键字修饰同步块,让线程获取某对象的锁实现多线程操作共享变量的同步外,还可以使用java.util.concurrent包.并且,juc包机制下的同步更灵活.juc包的所 ...

  2. juc包:使用 juc 包下的显式 Lock 实现线程间通信

    一.前置知识 线程间通信三要素: 多线程+判断+操作+通知+资源类. 上面的五个要素,其他三个要素就是普通的多线程程序问题,那么通信就需要线程间的互相通知,往往伴随着何时通信的判断逻辑. 在 java ...

  3. JUC包中的锁框架

    JUC包中的锁,包括:Lock接口,ReadWriteLock接口,LockSupport阻塞原语,Condition条件,AbstractOwnableSynchronizer/AbstractQu ...

  4. 转载:Java Lock机制解读

    Java Lock机制解读 欢迎转载: https://blog.csdn.net/chengyuqiang/article/details/79181229 1.synchronized synch ...

  5. 利用LOCK机制来定位前缀劫持者

    一.文章信息 作者:Tongqing Qiu, Lusheng Ji, Dan Pei等 单位:佐治亚理工学院.美国电话电报公司实验室.康奈尔大学等 来源:Conference on Usenix S ...

  6. Golang 包管理机制

    Golang 包管理机制 1. 历史 在go1.11之前, 并没有官方的包管理机制(Godep算个半官方), 主流的包管理机制有: GoVendor Glide Godep 在go1.11之后, 官方 ...

  7. JUC中Lock和ReentrantLock介绍及源码解析

    Lock框架是jdk1.5新增的,作用和synchronized的作用一样,所以学习的时候可以和synchronized做对比.在这里先和synchronized做一下简单对比,然后分析下Lock接口 ...

  8. JUC包中的分而治之策略-为提高性能而生

    一.前言 本次分享我们来共同探讨JUC包中一些有意思的类,包含AtomicLong & LongAdder,ThreadLocalRandom原理. 二.AtomicLong & Lo ...

  9. 前端工程化 - 剖析npm的包管理机制

    转自https://juejin.im/post/5df789066fb9a0161f30580c 现如今,前端开发的同学已经离不开 npm 这个包管理工具,其优秀的包版本管理机制承载了整个繁荣发展的 ...

随机推荐

  1. Netty 客户端使用指数退避机制实现重连

    指数退避 可以理解为每次重连失败时,就把重连时间设置为之前的指数级别.例如 2 秒,4 秒,8 秒...... 亚马逊AWS关于指数退避的两篇文章介绍 AWS 中的错误重试和指数退避 Exponent ...

  2. HTTP_2_HTTP协议概要

    http协议概要 HTTP 通信对象 通信方式 通信状态 定位资源 节省通信量 超文本传输协议 客户端与服务器端 请求和响应 不保存状态(借助cookie) 请求URI keep-alive/pipe ...

  3. 彻底搞懂Python切片操作

        在利用Python解决各种实际问题的过程中,经常会遇到从某个对象中抽取部分值的情况,切片操作正是专门用于完成这一操作的有力武器.理论上而言,只要条件表达式得当,可以通过单次或多次切片操作实现任 ...

  4. 【Android】Failed to convert @drawable/picture into a drawable

    刚使用 eclipse 遇到了这个问题,图片的效果未显示出来,上网查找后发现这其实不算是问题:重启下工程或 eclipse 就行了. PS: 直接运行工程也可以,不影响效果.

  5. 【iOS】Apple Mach-O Linker Error Linker command failed with exit code 1

    又遇到了这个问题,貌似之前遇到过……如图所示: 解决方法寻找中………… 在 Stack Overflow 找到了解决方法,如下: 参考链接:Apple Mach-O Linker Error

  6. 内容汇总(c语言)

    一,内容 常量(整型,浮点型,字符型,字符串型,符号常量) 变量(基本类型:整形,浮点型,字符型,枚举型:构造类型:数组,结构体,共用体:另外还有指针类型和NULL) 顺序结构 分支结构 循环结构 当 ...

  7. Git应用之eclipse解决冲突代码

    最近上班公司框架换成了微服务下面是eclipse 对代码进行管理 1.冲突代码 如果两个人在一个项目上同一文件上更改代码就会出现冲突现象 先用NewFile.jsp  文件做演示 打开eclipse从 ...

  8. 2、大型项目的接口自动化实践记录--接口测试简介及RequestsLibrary关键字简介

    1.接口测试简介 1)先简单介绍下接口测试,那么什么是接口测试呢? 百科的回答:接口测试是测试系统组件间接口的一种测试.接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点. 看起来有 ...

  9. Docker相关地址

    Docker社区版(CE)地址: https://hub.docker.com/search/?type=edition&offering=community Docker文档地址: http ...

  10. 【kafka】一、消息队列

    在高并发的应用场景中,由于来不及同步处理请求,接收到的请求往往会发生阻塞.例如,大量的插入.更新请求同时到达数据库,这会导致行或表被锁住,最后会因为请求堆积过多而触发“连接数过多的异常” 的错误.因此 ...