聊聊JUC包下的底层支撑类-AbstractQueuedSynchronizer(AQS)
聊聊JUC包下的底层支撑类-AbstractQueuedSynchronizer(AQS)
juc包下的一堆并发工具类是我们日常开发特别是面试中常被拿来问的八股文之一,为了工作也好,为了面试也罢,今天开始想尝试着把这些给大伙描述明白,所以开始写下这篇博文,如果后续要涉及每个常用类的源码的话可能会是一个系列,计划从比较底层的AQS聊起,然后结合ReentrantLock的源码来聊AQS独占锁的具体实现,以及加锁和释放锁的过程;然后再聊聊JUC包下其他类如CountDownLatch、CyclicBarrier、Phaser、ReadWriteLock、Semaphore、Exchanger以及LockSupport的使用和原理,有时间的话再结合CountDownLatch的源码来聊AQS共享锁的具体实现,接下来话不多说开始踏上揭秘AQS之旅
一、AQS是什么
- AQS全称AbstractQueuedSynchronizer即抽象队列同步器,可以理解成是一个可以实现锁的框架(基类),它可以实现共享和独占两种模式的锁,事实上juc包下很多关于锁的工具类也是基于AQS的;它提供了一些模板方法供子类实现拓展,并且本身结合底层的Unsafe类实现了基于cpu原语层的安全操作,从而实现在并发环境下的线程安全
二、AQS的实现原理
- AQS能作为基类来实现锁的功能主要原因来自于它维护的一个int类型的state变量和一个FIFO的双向队列;实现类可以根据自身的需求,通过控制state的值来决定线程是否需要阻塞,而双向队列用来存放没有争抢到锁资源的线程;并且AQS通过结合Unsafe类的能力封装了可以线程安全的操作state值的方法(一堆CAS的操作方法),这样程序员就可以只关注锁的使用而不必关注底层实现的细节了;
- AQS支持两种模式锁的实现,分别是独占锁和共享锁,独占锁的具体实现以ReentrantLock为代表,共享锁的实现诸如CountDownLatch、CyclicBarrier等
注:由于后续会介绍AQS的源码以及子类实现,所以这里只是大白话般的描述了一下AQS的原理,即两个关键:一个state一个双向队列,其实要展开还有许多细节要聊,考虑到这些细节后续源码里会有体现这里就不再表述了
三、AQS的源码简析
1、state变量
private volatile int state;
1、state是AQS提供的供子类拓展的一个同步状态,子类可以维护state的不同状态来实现不同效果的锁实现,如ReentrantLock就是通过维护state是否为0或1来表示锁的加解操作;
2、用volatile修饰主要是为了在并发环境下线程可见
2、Node内部类
- Node类是双向CLH队列的构成元素,其维护的thread变量就是没有争抢到锁的线程,然后还维护了CLH队列的其他几个关键信息,如当前Node的前置节点(prev)、后续节点(next)等,下面贴上Node的源码
static final class Node {
/** 表示当前节点正处于共享模式 */
static final Node SHARED = new Node();
/** 表示当前节点正处于独占模式 */
static final Node EXCLUSIVE = null;
/** waitStatus对应的值,表示线程已取消 */
static final int CANCELLED = 1;
/** waitStatus对应的值,指示后续线程需要取消标记*/
static final int SIGNAL = -1;
/** waitStatus对应的值,指示线程正在等待condition唤醒*/
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
static final int PROPAGATE = -3;
/**
* 等待状态,枚举值有1,0,-1,-2,-3分别对应上面的几个变量值,0表示以上状态都不是
*/
volatile int waitStatus;
/**
* 当前Node的前置节点
*/
volatile Node prev;
/**
* 当前Node的后继节点
*/
volatile Node next;
/**
* 与当前Node绑定的被阻塞的线程
*/
volatile Thread thread;
/**
* 下一个等待节点,Condition状态下要用到
*/
Node nextWaiter;
/**
* 如果节点在共享模式下等待,则返回true。
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
* 获取当前队列的前置节点
*
* @return the predecessor of this node
*/
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { // Used to establish initial head or SHARED marker
}
Node(Thread thread, Node mode) { // Used by addWaiter
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
}
3、AQS供子类拓展的模板方法
独占模式供子类实现的方法
tryAcquire(int) 尝试获取锁,获取成功返回true,失败返回false
tryRelease(int) 尝试释放锁,释放成功返回true,失败返回false
共享模式供子类实现的方法
tryAcquireshared(int)
尝试获取锁,负数表示失败; 0表示功,但没有剩余可用资源:正数表示成功,且有剩余资源。
tryReleaseshared(int)
尝试释放锁,成功返回true,失败返回false
上面简单介绍了一下AQS的原理以及源码的部分注释,接下来我会写一篇ReentrantLock源码解读的相关文章,来体验下AQS的实际用处
聊聊JUC包下的底层支撑类-AbstractQueuedSynchronizer(AQS)的更多相关文章
- juc包:使用 juc 包下的显式 Lock 实现线程间通信
一.前置知识 线程间通信三要素: 多线程+判断+操作+通知+资源类. 上面的五个要素,其他三个要素就是普通的多线程程序问题,那么通信就需要线程间的互相通知,往往伴随着何时通信的判断逻辑. 在 java ...
- Java语言Lang包下常用的工具类介绍_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 无论你在开发哪中 Java 应用程序,都免不了要写很多工具类/工具函数.你可知道,有很多现成的工具类可用,并且代码质量都 ...
- java扫描某个包下的所有java类并加载
最近在学习java的反射和注解,实际情景中需要扫描某个包下的所有java类,然后使用类加载器加载类. 基本思路,获得程序的路径扫描src下某个包内的子包和java类,实现也比较简单. 运行环境:win ...
- JUC 包下工具类,它的名字叫 LockSupport !你造么?
前言 LockSupport 是 JUC 中常用的一个工具类,主要作用是挂起和唤醒线程.在阅读 JUC 源码中经常看到,所以很有必要了解一下. 公众号:liuzhihangs ,记录工作学习中的技术. ...
- 【Java多线程】JUC包下的工具类CountDownLatch、CyclicBarrier和Semaphore
前言 JUC中为了满足在并发编程中不同的需求,提供了几个工具类供我们使用,分别是CountDownLatch.CyclicBarrier和Semaphore,其原理都是使用了AQS来实现,下面分别进行 ...
- JUC(三):JUC包下锁概念
线程不安全集合类 ArrayList List是线程不安全的集合类,底层是Object数组实现,初始化容量是10(其实是一个空数组,第一次扩容时,将数组扩容为10),其后每次扩容大小为当前容量的一半( ...
- java多线程系列11 juc包下的队列
队列分为两类 阻塞队列 BlockingQueue提供如下两个支持阻塞的方法: (1)put(E e): 尝试把e元素放如BlockingQueue中,如果该队列的元素已满,则阻塞该线程. ...
- Concurrent包下用过哪些类?
1.executor接口,使用executor接口的子接口ExecutorService用来创建线程池2.Lock接口下的ReentrantLock类,实现同步,比如三个线程循环打印ABCABCABC ...
- JUC包下Semaphore学习笔记
在Java的并发包中,Semaphore类表示信号量.Semaphore内部主要通过AQS(AbstractQueuedSynchronizer)实现线程的管理.Semaphore有两个构造函数,参数 ...
- JUC包下CyclicBarrier学习笔记
CyclicBarrier,一个同步辅助类,在API中是这么介绍的: 它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序中,这 ...
随机推荐
- LAPM概述及配置
一.LAMP概述 1.1LAMP的概念 LAMP架构是目前成熟的企业网站应用模式之一,指的是协同工作的一整套系统和相关软件,能够提供动态web站点服务及其应用开发环境 LAMP是一个缩写词,具体包括L ...
- SpringBoot&MyBatisPlus
5. SpringBoot 学习目标: 掌握基于SpringBoot框架的程序开发步骤 熟练使用SpringBoot配置信息修改服务器配置 基于SpringBoot完成SSM整合项目开发 5.1 入门 ...
- SpringBoot 02: 初识SpringBoot
1. SpringBoot 产生原因 spring, springmvc框架使用上的一些缺点: 需要使用的大量的配置文件 还需要配置各种对象 需要把使用的对象放入到spring容器中才能使用对象 需要 ...
- Day11.2:标签的使用
标签的使用 当我们在嵌套语句中,例如当我们在for的嵌套循环语句中,想要终止或重新开始当前循环以外的循环的时候,单独仅靠break和continue和还不够,需要在我们想要作用的循环语句处加上一个标签 ...
- PHP使用PHPmailer类和smtp发送邮件
开启邮件smtp服务 设置授权码 引入phpmailer类,smtp类本地下载https://github.com/PHPMailer/PHPMailer //下载PHPMailer并开启php_op ...
- SQL-GROUP BY语句在MySQL中的一个错误使用被兼容的情况
首先创建数据库hncu,建立stud表格. 添加数据: create table stud(sno varchar(30) not null primary key,sname varchar(30) ...
- day18-web工程路径
web工程路径 配置tomcat运行快捷键 tomcat启动的默认快捷键时shift+f10,可以自定义配置:file-setting-keymap-搜索run,找到右边写有shift+f10的选项, ...
- Bugku login1
打开是个普普通通的登录界面,盲猜是注入题,先看看源码吧,没找到什么有用的信息,那就先注册试试 注册admin就已经存在,可能待会就爆破admin的密码也可能,因为没有验证嘛 试试注册其他的 登录发现他 ...
- 【深入浅出 Yarn 架构与实现】4-1 ResourceManager 功能概述
前面几篇文章对 Yarn 基本架构.程序基础库.应用设计方法等进行了介绍.之后几篇将开始对 Yarn 核心组件进行剖析. ResourceManager(RM)是 Yarn 的核心管理服务,负责集群管 ...
- python(牛客)试题解析3 - 困难
导航 一.找到已经最大承重的背包内如何放入最大价值的物品的最优解 二.查找一个字符串中包含另外一个字符串(可打乱顺序)的次数三.计算正整数数组从头走到最后一个成员所需的最小步骤四.计算字符串非严格递增 ...