聊聊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)的更多相关文章

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

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

  2. Java语言Lang包下常用的工具类介绍_java - JAVA

    文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 无论你在开发哪中 Java 应用程序,都免不了要写很多工具类/工具函数.你可知道,有很多现成的工具类可用,并且代码质量都 ...

  3. java扫描某个包下的所有java类并加载

    最近在学习java的反射和注解,实际情景中需要扫描某个包下的所有java类,然后使用类加载器加载类. 基本思路,获得程序的路径扫描src下某个包内的子包和java类,实现也比较简单. 运行环境:win ...

  4. JUC 包下工具类,它的名字叫 LockSupport !你造么?

    前言 LockSupport 是 JUC 中常用的一个工具类,主要作用是挂起和唤醒线程.在阅读 JUC 源码中经常看到,所以很有必要了解一下. 公众号:liuzhihangs ,记录工作学习中的技术. ...

  5. 【Java多线程】JUC包下的工具类CountDownLatch、CyclicBarrier和Semaphore

    前言 JUC中为了满足在并发编程中不同的需求,提供了几个工具类供我们使用,分别是CountDownLatch.CyclicBarrier和Semaphore,其原理都是使用了AQS来实现,下面分别进行 ...

  6. JUC(三):JUC包下锁概念

    线程不安全集合类 ArrayList List是线程不安全的集合类,底层是Object数组实现,初始化容量是10(其实是一个空数组,第一次扩容时,将数组扩容为10),其后每次扩容大小为当前容量的一半( ...

  7. java多线程系列11 juc包下的队列

    队列分为两类  阻塞队列 BlockingQueue提供如下两个支持阻塞的方法:   (1)put(E e): 尝试把e元素放如BlockingQueue中,如果该队列的元素已满,则阻塞该线程.   ...

  8. Concurrent包下用过哪些类?

    1.executor接口,使用executor接口的子接口ExecutorService用来创建线程池2.Lock接口下的ReentrantLock类,实现同步,比如三个线程循环打印ABCABCABC ...

  9. JUC包下Semaphore学习笔记

    在Java的并发包中,Semaphore类表示信号量.Semaphore内部主要通过AQS(AbstractQueuedSynchronizer)实现线程的管理.Semaphore有两个构造函数,参数 ...

  10. JUC包下CyclicBarrier学习笔记

    CyclicBarrier,一个同步辅助类,在API中是这么介绍的: 它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point).在涉及一组固定大小的线程的程序中,这 ...

随机推荐

  1. Git 分支管理策略汇总

    原文链接: Git 分支管理策略 最近,团队新入职了一些小伙伴,在开发过程中,他们问我 Git 分支是如何管理的,以及应该怎么提交代码? 我大概说了一些规则,但仔细想来,好像也并没有形成一个清晰规范的 ...

  2. Python基础之网络编程:2、OSI协议之七层协议

    目录 Python基础之网络编程 一.网络编程前戏 二.OSI七层协议 简介: 1.物理连接层 2.数据链路层 网络相关专业名词 3.网络层 4.传输层 Python基础之网络编程 一.网络编程前戏 ...

  3. 工作总结:kafka踩过的坑

    餐饮系统每天中午和晚上用餐高峰期,系统的并发量不容小觑.公司规定各部门都要轮流值班,防止出现线上问题时能够及时处理. 后厨显示系统属于订单的下游业务. 用户点完菜下单后,订单系统会通过发 Kafka ...

  4. 2022春每日一题:Day 7

    题目:Fire 先预处理出每个F蔓延的时间,再bfs走迷宫. 代码: #include <cstdio> #include <cstdlib> #include <cst ...

  5. 面试官不按套路,竟然问我Java线程池是怎么统计线程空闲时间?

    背景介绍: 你刚从学校毕业后,到新公司实习,试用期又被毕业,然后你又不得不出来面试,好在面试的时候碰到个美女面试官! 面试官: 小伙子,我看你简历上写的项目中用到了线程池,你知道线程池是怎样实现复用线 ...

  6. 【云原生 · DevOps】DevOps 解决方案

    DevOps 解决方案 1.1 容器化 CI/CD 1.2 容器化流水线 1.3 深度集成 Jenkins 1.4 灰度发布 1.5 制品库设计 1.6 DevOps 安全 1.6.1 CI/CD 安 ...

  7. NET 6 实现滑动验证码(一)、创建工程

    目录 实现滑动验证码的目的 创建.NET 6工程 实现滑动验证码的目的 传统验证码实现起来比较简单,但在OCR技术越来越成熟的情况下,验证码的破解难度越来越低,但如果将验证码难度加高(各种干扰背景,扭 ...

  8. [Polkadot] 波卡链学习笔记

    前言 早已听闻波卡链大名,但从未真正静下心来了解.最近难得有些属于自己的时间了,故将学习到的记录下来. 介绍 相信大家对波卡链都有些许了解,在这我就长话短说,简单介绍一下. Polkadot是由Web ...

  9. 第2-4-8章 规则引擎Drools实战(1)-个人所得税计算器

    目录 9. Drools实战 9.1 个人所得税计算器 9.1.1 名词解释 9.1.2 计算规则 9.1.2.1 新税制主要有哪些变化? 9.1.2.2 资较高人员本次个税较少,可能到年底扣税增加? ...

  10. 安装mySql 出现 one more product requirements have not been satisified

    安装mySql 出现 one more product requirements have not been satisified 原因是缺少一些依赖环境. 在弹出的对话框中点击 否. 然后点击执行, ...