1.  前言

Java中好多地方用到AbstractQueuedSynchronizer(PS:简称AQS),比如ReentrantLock、线程池,这部分在面试的时候也经常被问到,今天以ReentrantLock为例,通过源码来加深对AQS的理解

2.  lock

通常,我们的用法是这样的:

那么lock(),unlock()到底做了什么,我们并不知晓,接下来一步一步揭开她的神秘面纱

2.1.  lock

可以看到,ReentrantLock默认是NonfairSync(非公平锁)

2.2.  NonfairSync

可以看到,首先判断同步状态是否是0,如果是0则临界资源没有被占用,并且将状态设为1,当前线程获得这个资源,可以访问;否则,调用acquire(1)方法尝试获取资源的访问控制权。

2.3.  tryAcquire

尝试再获取一次

如果当前同步状态是0,则跟之前相同,将状态置为1,当前线程获得访问权,返回true

如果当前资源的所有者线程就是当前线程,则状态加1,当前线程仍然获得访问权,返回true

如果以上情况都不是(PS:资源被别的线程占用着),则返回false

2.4.  acquireQueued

如果上一步tryAcquire方法返回false,则继续调用acquireQueued方法将线程添加到队列中(PS:链表的尾部)

在添加到链表之前,先封装成Node对象

将当前线程构造成Node对象,节点的模式是排它的,然后将其加到链表的尾部(或是说叫队列),最后将该结点返回

这里有两个特殊的节点:等待队列的头结点 和 等待队列的尾结点

接下来,将刚才构造的节点加到队列中

如果当前节点的前驱节点是头结点(head),并且当前节点再次尝试获取资源(tryAcquire方法),恰好成功了,于是皆大欢喜

如果当前节点的前驱节点既不是head,而且当前节点也没有抢占到资源,则循环直到前驱节点的状态变成SIGNAL,则挂起当前线程

3.  unlock

如果资源的所有者线程不是当前线程的话,则抛出异常

如果当前资源同步状态减1恰好是0,则成功释放,同步状态置为0,资源所有者线程置为null,唤醒head的后继节点

4.  小结

加锁

1、默认非公平锁(PS:当前线程不是直接加到等待队列中,而是先尝试获取一次,如果不成功则加到队列中,在加的时候还会尝试一次)

2、临街资源有一个同步状态,0表示当前没有线程占用,则可以直接可以获取到资源(加锁成功)

3、如果资源所有者线程就是当前线程,则状态加1,仍然可以获得锁

3、加锁成功以后,将同步状态置为1,资源所有者线程置为当前线程

4、不成功,则封装成Node加入到等待队列(链表)中,此时,还会像前面一样再尝试(抢占)一次

5、抢占不成功,加到等待队列中,线程挂起

解锁

1、资源所有者线程不是当前线程,则抛异常

2、唤醒下一个结点

AbstractQueuedSynchronizer源码分析(ReentrantLock锁的实现)的更多相关文章

  1. Java并发系列[2]----AbstractQueuedSynchronizer源码分析之独占模式

    在上一篇<Java并发系列[1]----AbstractQueuedSynchronizer源码分析之概要分析>中我们介绍了AbstractQueuedSynchronizer基本的一些概 ...

  2. AbstractQueuedSynchronizer源码分析

    AbstractQueuedSynchronizer源码分析 前提 AQS(java.util.concurrent.locks.AbstractQueuedSynchronizer)是并发编程大师D ...

  3. Java并发系列[3]----AbstractQueuedSynchronizer源码分析之共享模式

    通过上一篇的分析,我们知道了独占模式获取锁有三种方式,分别是不响应线程中断获取,响应线程中断获取,设置超时时间获取.在共享模式下获取锁的方式也是这三种,而且基本上都是大同小异,我们搞清楚了一种就能很快 ...

  4. Java并发系列[4]----AbstractQueuedSynchronizer源码分析之条件队列

    通过前面三篇的分析,我们深入了解了AbstractQueuedSynchronizer的内部结构和一些设计理念,知道了AbstractQueuedSynchronizer内部维护了一个同步状态和两个排 ...

  5. 鸿蒙内核源码分析(互斥锁篇) | 比自旋锁丰满的互斥锁 | 百篇博客分析OpenHarmony源码 | v27.02

    百篇博客系列篇.本篇为: v27.xx 鸿蒙内核源码分析(互斥锁篇) | 比自旋锁丰满的互斥锁 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁当立贞 ...

  6. 鸿蒙内核源码分析(自旋锁篇) | 当立贞节牌坊的好同志 | 百篇博客分析OpenHarmony源码 | v26.02

    百篇博客系列篇.本篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 当立贞节牌坊的好同志 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 当立贞节牌坊 ...

  7. [源码分析]ReentrantLock & AbstractQueuedSynchronizer & Condition

    首先声明一点: 我在分析源码的时候, 把jdk源码复制出来进行中文的注释, 有时还进行编译调试什么的, 为了避免和jdk原生的类混淆, 我在类前面加了"My". 比如把Reentr ...

  8. 【JDK】JDK源码分析-ReentrantLock

    概述 在 JDK 1.5 以前,锁的实现只能用 synchronized 关键字:1.5 开始提供了 ReentrantLock,它是 API 层面的锁.先看下 ReentrantLock 的类签名以 ...

  9. 多线程之美5一 AbstractQueuedSynchronizer源码分析<一>

    AQS的源码分析 目录结构 1.什么是CAS ? 2.同步器类结构 3.CLH同步队列 4.AQS中静态内部类Node 5.方法分析 ​ 5.1.acquire(int arg ) ​ 5.2.rel ...

  10. Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析

    经过前面几篇文章的铺垫,今天我们终于要看看AQS的庐山真面目了,建议第一次看AbstractQueuedSynchronizer 类源码的朋友可以先看下我前面几篇文章: <Java并发包源码学习 ...

随机推荐

  1. Spark实战

    实战 数据导入Hive中全量: 拉链增量:用户.商品表数据量大时用 拉链表动作表 增量城市信息 全量 需求一: 获取点击.下单和支付数量排名前 的品类 ①使用累加器: click_category_i ...

  2. ImCash:论拥有靠谱数字钱包的重要性!

    数字货币被盗已经不是什么新鲜事,前有交易所币安被黑客攻击,Youbit破产,后有“钓鱼邮件“盗号木马,安全对于数字货币用户来讲至关重要. 现行市场痛点:   2017年9月以太坊Parity钱包的漏洞 ...

  3. babel分析

    现在都用 ES6 新语法以及 ES7 新特性来写应用了,但是浏览器和相关的环境还不能友好的支持,需要用到 Babel 转码器来转换成 ES5 的代码 相信大家都看到过如下的名词: babel-pres ...

  4. VB.NET或C#报错:You must hava a license to use this ActiveX control.

    VB.NET或者C# winform开发时,如果使用了Microsoft Visual Basic 6.0 ActiveX,并动态创建该控件实例,那么程序移植到没有安装Visual Basic 6.0 ...

  5. jdk12+tomcat9 配置

    jdk12 没有了jre的配置   直接配置path就可以了 tomcat常规配置,只是启动的时候麻烦一点   需要重新写入jdk jre jvm 到server.bat文件 参考文章: https: ...

  6. [Educational Round 10][Codeforces 652F. Ants on a Circle]

    题目连接:652F - Ants on a Circle 题目大意:\(n\)个蚂蚁在一个大小为\(m\)的圆上,每个蚂蚁有他的初始位置及初始面向,每个单位时间蚂蚁会朝着当前面向移动一个单位长度,在遇 ...

  7. PHP实现微信模板消息发送给指定用户

    使用公众号的模板消息功能,必须是认证过的服务号,需要发送微信号的openid,同一微信号在不同公众号下的openid是不同的,在公众号下是唯一的,获取不到微信号 进入公众平台  功能->模板消息 ...

  8. SharePoint 更改管理帐户密码步骤

    // https://wenku.baidu.com/view/0fffab761ed9ad51f01df2df.html \

  9. 问题:这个新申请的内存为什么不能free掉?(已解决)

    一.问题描述 先上代码, /*** 省略 ***/ uChar *base64 = NULL; /*** 省略 ***/ base64 = (一段内存) /*** 省略 ***/ base64 = s ...

  10. Java中不定项参数(可变参数)的使用

    Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理. 注意事项:   1)不定项参数必须放在参数列表最后一个.   2)不定项参数只能有一个(多 ...