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. toString

    在java中使用toString: 如果在Java在输出定义一个Person类 然后实例化person  per 直接用system.out.println(per);无法得到我们想要的实例化内容 p ...

  2. PC网站转换成手机版

    博客地址:https://www.cnblogs.com/zxtceq/p/5714606.html 一天完成把PC网站改为自适应!原来这么简单! http://www.webkaka.com/blo ...

  3. Tips_关闭按钮的简单实现 && Felx实现水平垂直居中

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. 非vue-cli的花括号闪现问题

    <div id="app" v-cloak></div>[v-cloak] { display: none;}这种方式可以解决网速较慢,vue.js文件还没 ...

  5. js array 对象

    Javascript 对象: Array 对象:数组 创建方法: 1, var a = new Array() 2,var a = new Array(3) 3,var a = new Array(“ ...

  6. MySQL8主从配置

    最近在看MySQL的主从配置,罗列一下过程. 一.环境介绍 我使用的是两个MySQL8.0.13Windows版,Master和Slave安装的在一个机器上,Master库的端口为3306,Slave ...

  7. swust oj 1016

    插入排序算法实现 1000(ms) 10000(kb) 2613 / 6080 插入排序算法实现. 输入 第一行是待排序数据元素的个数: 第二行是待排序的数据元素. 输出 一趟直接插入排序算法结果. ...

  8. Luogu P1894 [USACO4.2]The Perfect Stall

    传送门 是道绿题???二分图(网络流)不应该是蓝打底??? 这题浏览一遍就知道是二分图(网络流)算法喽,二分图代码太短,不想写(←这人???),所以就拿网络流练练手. 设源点S=0,汇点T=n+m+1 ...

  9. SSIS - 11.For循环容器

    一.For循环容器中的3个循环变量 For循环容器,类似于编程语言中的For,用于重复执行容器内的任务,直到条件返回为False.与编程语言类似,For循环容器也需要定义以下3种循环属性: 注: 必须 ...

  10. SSIS - 9.文件系统任务

    文件系统任务是用来操作服务器上的文件和目录的.比如,可以新建任务来创建.复制.删除或移动一个文件或一个目录. 一.操作和属性 一个文件系统可以定义如下10种操作. 所有的操作包含Name, Descr ...