AQS源码探究_02 AQS简介及属性分析

简介: 1. 简介

AQS的全称是AbstractQueuedSynchronizer,它的定位是为Java中几乎所有的锁和同步器提供一个基础框架。


AQS是基于FIFO的队列实现的,并且内部维护了一个状态变量state,通过原子更新这个状态变量state即可以实现加锁解锁操作。


2. 主要内部类Node

static final class Node {
    // 标识一个节点是共享模式
    static final Node SHARED = new Node();
    // 标识一个节点是互斥模式
    static final Node EXCLUSIVE = null;
    // 标识线程已取消(表示当前节点处于取消状态)
    static final int CANCELLED =  1;
    // 标识后继节点需要唤醒(表示当前节点需要唤醒他的后继节点)
    static final int SIGNAL    = -1;
    // 标识线程等待在一个条件上
    static final int CONDITION = -2;
    // 标识后面的共享锁需要无条件的传播(共享锁需要连续唤醒读的线程)
    static final int PROPAGATE = -3;
    // 当前节点保存的线程对应的等待状态(node状态可选值:0,SIGNAL,CANCELLED,CONDITION,PROPAGATE)
    // waitStatus == 0 默认状态
    // waitStatus > 0 取消状态
    // waitStatus == -1 表示当前node如果是head节点时,释放锁之后需要唤醒它的后继节点
    volatile int waitStatus;
    // 前一个节点(前驱):用于node构建 FIFO队列~
    volatile Node prev;
    // 后一个节点(后驱):用于node构建 FIFO队列~
    volatile Node next;
    // 当前node节点封装的线程
    volatile Thread thread;
    // 下一个等待在条件上的节点(Condition锁时使用)
    Node nextWaiter;
    // 是否是共享模式
    final boolean isShared() {
        return nextWaiter == SHARED;
    }
    // 获取前一个节点
    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
        // 把共享模式还是互斥模式存储到nextWaiter这个字段里面了
        this.nextWaiter = mode;
        this.thread = thread;
    }
    // 节点的构造方法
    Node(Thread thread, int waitStatus) { // Used by Condition
        // 等待的状态,在Condition中使用
        this.waitStatus = waitStatus;
        this.thread = thread;
    }
}

双链表结构,节点中保存着当前线程、前一个节点、后一个节点以及线程的状态等信息。

3. 主要属性

// 队列的头节点: 任何时刻,头结点对应的线程就是当前持锁线程~
private transient volatile Node head;
// 队列的尾节点:(阻塞队列不包含头结点head,是从head.next 开始,到 tail 结束,这个区间是阻塞队列~)
private transient volatile Node tail;
// 控制加锁解锁的状态变量
// 独占模式下:0 表示未加锁状态, >0 表示已加锁状态
private volatile int state;

定义了一个状态变量和一个队列,状态变量用来控制加锁解锁,队列用来放置等待的线程。

注意:这几个变量都要使用volatile关键字来修饰,因为是在多线程环境下操作,要保证它们的值修改之后对其它线程立即可见。

这几个变量的修改是直接使用的Unsafe这个类来操作的:

// 获取Unsafe类的实例,注意这种方式仅限于jdk自己使用,普通用户是无法这样调用的
private static final Unsafe unsafe = Unsafe.getUnsafe();
// 状态变量state的偏移量
private static final long stateOffset;
// 头节点的偏移量
private static final long headOffset;
// 尾节点的偏移量
private static final long tailOffset;
// 等待状态的偏移量(Node的属性)
private static final long waitStatusOffset;
// 下一个节点的偏移量(Node的属性)
private static final long nextOffset;
static {
    try {
        // 获取state的偏移量
        stateOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
        // 获取head的偏移量
        headOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
        // 获取tail的偏移量
        tailOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
        // 获取waitStatus的偏移量
        waitStatusOffset = unsafe.objectFieldOffset
            (Node.class.getDeclaredField("waitStatus"));
        // 获取next的偏移量
        nextOffset = unsafe.objectFieldOffset
            (Node.class.getDeclaredField("next"));
    } catch (Exception ex) { throw new Error(ex); }
}
// 调用Unsafe的方法原子更新state
protected final boolean compareAndSetState(int expect, int update) {
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

4. 父类属性

AQS还用到了其父类AbstractOwnableSynchronizer的一些属性:

// 独占模式下:表示当前持有锁的线程~
private transient Thread exclusiveOwnerThread;


相关文章
|
编解码 数据挖掘 Windows
Office 2021 for Windows 简体中文 官网下载地址
Microsoft Office 2021 Pro Plus专业增强版包括对Word、Excel、PowerPoint、Outlook、OneNote、Publisher、Access、Teams的更新。
1921 0
|
8月前
|
机器学习/深度学习 人工智能 算法
Stable Virtual Camera:2D秒变3D电影!Stability AI黑科技解锁无限运镜,自定义轨迹一键生成
Stable Virtual Camera 是 Stability AI 推出的 AI 模型,能够将 2D 图像转换为具有真实深度和透视感的 3D 视频,支持自定义相机轨迹和多种动态路径,生成高质量且时间平滑的视频。
453 0
Stable Virtual Camera:2D秒变3D电影!Stability AI黑科技解锁无限运镜,自定义轨迹一键生成
|
监控 Java 数据库
Spring事务中的@Transactional注解剖析
通过上述分析,可以看到 `@Transactional`注解在Spring框架中扮演着关键角色,它简化了事务管理的复杂度,让开发者能够更加专注于业务逻辑本身。合理运用并理解其背后的机制,对于构建稳定、高效的Java企业应用至关重要。
428 0
|
Linux 网络安全 数据安全/隐私保护
|
存储 缓存 NoSQL
基于SpringBoot+Redis解决缓存与数据库一致性、缓存穿透、缓存雪崩、缓存击穿问题
这篇文章讨论了在使用SpringBoot和Redis时如何解决缓存与数据库一致性问题、缓存穿透、缓存雪崩和缓存击穿问题,并提供了相应的解决策略和示例代码。
417 0
|
Prometheus 监控 Cloud Native
Docker下Prometheus和Grafana三部曲之三:自定义监控项开发和配置
本文详细讲述了业务系统如何将自定义的监控项上报到prometheus,并且在Grafana上配置监控项展示上报的自定义数据
653 0
Docker下Prometheus和Grafana三部曲之三:自定义监控项开发和配置
|
监控 小程序 Java
《优化接口设计的思路》系列:第五篇—接口发生异常如何统一处理
大家好!我是sum墨,一个一线的底层码农,平时喜欢研究和思考一些技术相关的问题并整理成文,限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。
940 0
《优化接口设计的思路》系列:第五篇—接口发生异常如何统一处理
|
Web App开发 开发框架 前端开发
Fastadmin是一款基于thinkphp和bootstrap的快速后台开发框架
Fastadmin是一款基于thinkphp和bootstrap的快速后台开发框架
422 2
|
easyexcel Java 数据库
excel多sheet页的导入
excel多sheet页的导入
297 0