AQS源码解析 2.简介 内部核心结构

news2025/1/18 21:19:16

AQS源码解析—简介 & 内部核心结构

AQS内部结构

简介

  • AbstractQueuedSynchronizer:AQS,抽象队列同步器。主要是为了解决线程锁竞争的问题。

  • AQS 原理图如下,其本质是一个双向链表/队列

    image-20221024114744738

  • 多线程抢锁内部数据结构,如下

    image-20221024114755398

核心内部类Node

    static final class Node {
        
        // 枚举:共享模式
        static final Node SHARED = new Node();
        
        // 枚举:独占模式
        static final Node EXCLUSIVE = null;
		
        /*
         * 下面的这几个int类型的常量表示节点的状态值
         */
        
        // 表示当前节点处于取消状态
        static final int CANCELLED =  1;
        
        // 表示当前节点需要唤醒它的后继节点,(signal表示的其实是后继节点的状态,需要当前节点去唤醒它...)
        static final int SIGNAL    = -1;
        
        // ReentrantLock没有用到 等待队列(Condition)中的节点状态为 -2
        static final int CONDITION = -2;
    	
        // ReentrantLock没有用到 只在CountDownLatch中的doReleaseShared这个方法中会切换到这个状态
        static final int PROPAGATE = -3;
  
        /*
         * 表示node的状态,可选值(0, SIHGNAL(-1), CANCLLED(1), CONDITION(-2), PROPAGATE(-3)) ReentrantLock中只用到了前三个值
         * waitStatus = 0 默认状态
         * waitStatus > 0 取消状态
         * waitStatus = -1 表示当前Node如果是head节点时 释放锁之后需要唤醒后继节点
         */
        volatile int waitStatus;
		
        /*
         * 因为node需要构建成 fifo 队列,所以需要当前节点的前继节点和后继节点
         */
        // Node的前继节点
        volatile Node prev;

        // Node的后继节点
        volatile Node next;
        
        // Node内部封装的线程
        volatile Thread thread;
        
        // ReentrantLock没有用到,在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;
        }

        // 建立初始头部或SHARED标记
        Node() { 
        }
		
        // addWaiter使用的构造方法
        Node(Thread thread, Node mode) {
            // 把共享模式还是互斥模式存储到nextWaiter这个字段里面了
            this.nextWaiter = mode;
            this.thread = thread;
        }
		
        // addConditionWaiter使用的构造方法
        Node(Thread thread, int waitStatus) {
            // 等待的状态,在Condition中使用
            this.waitStatus = waitStatus;
            this.thread = thread;
        }     
    }

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

核心属性

 	// 队列头结点,任何时刻头结点对应的线程都是当前持锁线程
	private transient volatile Node 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);
    }

父类属性

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

    /*
     * 继承父类的属性
     * 独占模式下:表示当前持有锁的线程
     */
    private transient Thread exclusiveOwnerThread;

参考

  • 视频参考
    • b站_小刘讲源码付费课
  • 文章参考
    • shstart7_AQS源码解析2.内部核心结构与lock过程
    • 兴趣使然的草帽路飞_AQS源码探究_02 AQS简介及属性分析
    • 肆华_AQS阅读理解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/23600.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

m基于matlab的站点休眠中继CDMA网络动态节能控制算法仿真与性能分析

目录 1.算法概述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法概述 蜂窝网络不仅需要能够为用户提供高质量的语音服务,而且要能够提供大量的数据传输服务,这就决定了蜂窝网络的发展必须要进一步提高系统容量和高速数据速率覆盖&…

银行人总结5个影响系统性能的因素,怕是很多人都会忽略

性能测试往往在投产上线前开展,无法对整个系统变更进行全面的覆盖测试,因此性能测试需求提出十分关键。 性能测试需求交付过程中,需要对开发团队提出的测试需求进行审查,重点分析交付的测试需求是否充分覆盖了影响系统性能的因素…

Cisco Packet Tracer HSRP技术练习

公司拓扑图 交换机配置参数表,如表2-3-4所示。 表2-3-4 交换机配置参数表 交换机 vlan IP地址 hsrp组 虚拟网关地址 核心1 Vlan 10 172.16.10.252/24 10 172.16.10.254/24 Vlan20 172.16.20.252/24 20 172.16.20.254/24 核心2 Vlan 10 172.16.10.…

基于springboot+vue的高校迎新系统(前后端分离)

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

Android App开发实战项目之仿手机QQ动感影集动画播放(附源码和演示视频 可直接使用)

需要图片集和源码请点赞关注收藏后评论区留言~~~ 动感影集就是只要用户添加一张图片,动感影集就能给每张图片渲染不同的动画效果,让原本静止的图片变得活泼起来,辅以各种精致的动画特效,营造一种赏心悦目的感觉。 一、需求描述 …

Cadence Allegro PCB设计88问解析(十八) 之 Allegro中差分规则设置

一个学习信号完整性仿真的layout工程师 我们在进行layout设计时,进行会遇到差分信号的layout,像USB和HDMI等,是需要控制阻抗的,那么我们在走线的时候,也需要从电器规则和物理规则上设置差分要求,今天和大家…

K8S kube-scheduler-master CreateContainerError 问题解决及思路

错误信息1: kubectl get pods 发现pod状态一直在 runing-error-CrashLoopBackOff -循环 解决方法:1,查看日志。 kubectl logs pods web-674477549d-zx8gmkubectl describe pods web-674477549d-zx8gm 没有发现错误,并且服务器资源…

2023年MBA/MPA/MEM联考笔试答题抓分点

距离今年的管理类联考还有一个月左右的时间,在最后这个阶段,除了继续稳固的提升自身应试的基本能力之外,一些细节和技巧也要特别关注和留意,说不定可以在考场上帮自己更好的抓分。今天杭州达立易考教育为大家整理主观题答题的五个…

链表OJ题+牛客题

目录 206.反转链表 876.链表的中间节点 链表中倒数第k个节点 CM11链表分割 OR36 链表的回文 206.反转链表 给你单链表的头节点head,请你反转链表,并返回反转后的链表。 实现如下结果: 思路: 取链表中的节点头插: 代码&#…

操作系统的奋斗(二)

第二章 进程与线程2.1进程与线程2.1.1进程的概念、特征、状态与转换2.1.2进程的组织、控制、通信2.1.3进程和多线程模型2.2处理机调度2.2.1调度的概念、目标、实现2.2.2典型的调度算法2.2.3进程切换2.3同步与互斥2.3.1同步与互斥的基本概念2.3.2实现临界区互斥的基本办法2.3.3互…

IPv6与VoIP——配置Cisco CME实现VoIP实验

作者简介:一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 目录 前言 一.配置Cisco CME实现VoIP 1.实验环境 2.需要设备 Cisco P Co…

解决TypeError: type complex doesn‘t define __round__ method

在调整学习率的时候遇到的一个bug,现已解决。 首先看这个bug说的是:类型complex(复数:ij)类型不能使用round函数。 为啥不能使用呢: round函数是四舍五入,round(lr,10)就是取lr四舍五入后十位。而复数不能…

分享一套宾馆客房管理系统源码,功能完善,代码完整

淘源码:国内专业的免费源码下载平台 需要源码学习可私信 基本介绍: 本宾馆管理系统是一套成熟的客房管理软件,综合了国内多家同行业软件的优点。具有操作简单、功能全面。 适用于酒店、宾馆、招待所等提供住宿服务的企业。 功能简介: 包括入…

文献学习02_A Survey on Deep Learning for Named Entity Recognition_20221121

论文信息 Subjects: Computation and Language (cs.CL) (1)题目:A Survey on Deep Learning for Named Entity Recognition (命名实体识别的深度学习研究综述) (2)文章下载地址:ht…

私域流量对企业的好处

互联网商业人群在这种时代里,不断寻求突破,开拓创新,很好的将线上和线下结合起来,其中涌现了很多“互联网”模式以及一些新的概念。 比如社交电商、社群零售、私域流量等。这些新互联网商业概念,催生了很多大型企业&…

公众号免费网课查题方法

公众号免费网课查题方法 本平台优点: 多题库查题、独立后台、响应速度快、全网平台可查、功能最全! 1.想要给自己的公众号获得查题接口,只需要两步! 2.题库: 题库:题库后台(点击跳转&#xf…

charles抓包配置具体操作步骤

Charles主要功能 截取Http和Https网络封包 支持重发网络请求,方便后端调试 支持修改网络请求参数 支持网络请求的截获并动态修改 支持模拟慢速网络 Charles下载安装 charles下载地址:https://www.charlesproxy.com/download/ 注: 浏览…

匹配系统(下)

创建SpringCloud目录 目录 创建SpringCloud目录 创建我们的两个子项目 实现两个Interface Config网关 放行完事两个Api 封装后端逻辑 对接我们的匹配系统 修改数据库-天梯分 更改数据库对应的一些修改 实现我们匹配之后的逻辑的思路 具体实现过程 关于线程锁 来进…

【扩展阅读之编译和解释语言的区别】

扩展阅读之编译和解释语言的区别1 本节目标2 解释型语言和编译型语言3 标识符、关键字、保留字1 本节目标 知道解释型语言和编译型语言的特点知道标识符不能是关键字或保留字 2 解释型语言和编译型语言 程序语言翻译成机器语言的工具被称为翻译器。翻译器翻译的方式有两种&a…

# 自用集群搭建Cluster

Redis集群 MySQL集群 Zookeeper集群 server.1192.168.81.133:2881:3881 server.2192.168.81.133:2882:3882 server.3192.168.81.133:2883:3883 $ cd …/zkdata $ touch myid $ echo “1”>>myid echo “2”>>myid echo “3”>>myid vim zoo.cfg dataDi…