AQS源码解析(ReentrantLock)

news2024/9/24 13:23:07

        什么是AQS:Juc中的大多数同步器都是围绕着一些相同的基础行为,比如等待队列,条件队列,共享,独占获取变量这些行为,抽象出来就是基于AQS(AbstractQueuedSynchronizer)实现的。所以可以把AQS看成这些行为的一个整合。

        管程:管程是指管理共享变量,以及对共享变量操作的过程,以此来让它们支持并发。不管是sychronized还是ReentrantLock,都是基于MESA的管程模型实现的

入口等待队列:

        如果共享资源已经被占用,那么其余线程会被阻塞在里面,等待唤醒的时候才会再去竞争共享变量

条件变量等待队列:

        ReentrantLock中的Condition.await()的时候会进入对应的条件队列,调用signal()的时候会从条件队列进入到入口等待队列,sychronized中只有一个条件等待队列(因为没有Condition),这个队列实现了阻塞唤醒的功能。

      来看一下ReentrantLock.lock()中的关键代码

//尝试获取共享变量 
protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        //获取共享变量
        int c = getState();
        if (c == 0) {
            //cas尝试修改共享变量,如果成功了,那么将独占线程设置成当前线程
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            //锁重入逻辑,state+1
            setState(c + acquires);
            return true;
        }
        return false;
}

           tryAcquire方法中做的事情就是尝试去获取共享变量state(默认是0),如果获取到了那么通过cas将其修改成1,然后将其独占线程设置成当前线程,如果是锁重入,那么就将state再次+1,如果是多个线程进来,未获取到共享变量的线程,接下来会走到addWaiter中的enq()方法。

    //构造阻塞队列
    private Node enq(final Node node) {
        for (;;) {
            //第一次进来的时候肯定是null
            Node t = tail;
            if (t == null) { // Must initialize
                //通过cas设置头尾指针,都指向空Node(首节点)
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else {
                //第二次循环的时候,首结点已经构造完
                node.prev = t;
                //将尾指针指向该节点,并且绑定和首节点之间的指向关系
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

          enq()主要用来创建阻塞队列,构造空节点为头结点,并且将头结点的next变量指向传入的节点,将传入节点的prev变量指向头结点。如果已经构造过了阻塞队列,那么会在addWaiter中就直接创建节点之间的指向关系,然后返回。并且会跳至acquireQueued方法

    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        for (;;) {
            //前置节点如果是头结点,那么会再次去竞争共享资源
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
            //如果竞争成功,那么就会将头结点设置成该节点,并且将其线程和prev全部置空
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            //如果获取不到,那么就调用lockSupport.park进行阻塞,等到释放锁的时候被唤醒
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
      
}

        构造完阻塞队列入队之后,并不会立马就进行阻塞,而是会先判断他的前置节点是否是头结点,如果是,那么会再一次进行资源竞争(所以如果是公平锁,被唤醒之后会将前置节点是头结点的那个节点出队然后获取资源)。如果获取不到那么就调用lockSupport.park()进行阻塞。

        公平锁和非公平锁的区别:公平锁只会从阻塞队列里面按照入队顺序一个个的去竞争,非公平锁在释放锁的时候,如果有线程进来了,那么也会去立马抢占锁,并不会按顺序入到阻塞队列中,这是两者的最大区别。

        条件队列的源码可以自行再去解读一下(主要就是调用了await和signal方法,await的时候入条件队列,signal的时候从条件队列转到阻塞队列),本文主要讲解了获取锁的整个流程。但是现在一般用的都是微服务架构,分布式锁的实现和源码解析可以参考下文 分布式锁源码解析

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

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

相关文章

昇思学习打卡-18-LLM原理与实践/MindNLP ChatGLM-6B StreamChat

文章目录 模型介绍技术特点运行效果 模型介绍 ChatGLM-6B模型是一个开源的、支持中英双语的对话语言模型,由清华大学和智谱AI联合研发。 技术特点 模型量化技术:ChatGLM-6B结合了模型量化技术,使得用户可以在消费级的显卡上进行本地部署。…

C++动态内存的管理

今天来分享C动态内存管理相关知识,闲言勿谈,直接上干货。 1. 动态内存的开辟和销毁(new和delete) (1)前置知识:我们知道c语言有malloc和calloc和realloc三个函数可以进行动态的开辟内存,那么它们有什么区别呢?首先是…

Module2 DRC Basics

材料链接 calibre_rule_writing_2007 - 道客巴巴https://www.doc88.com/p-330763936895.html Calibre DRC介绍 Calibre nmDRC流程 找寻,查看,纠正DRC冲突的一个完整的过程: 从Layout输入,加上svrf文件,一起输入进nmDRC软件; 输出DRC result数据,summary report,tr…

【经验分享】关于静态分析工具排查 Bug 的方法

文章目录 编译器的静态分析cppcheck安装 cppcheck运行 cppcheck 程序员的日常工作,不是摸鱼扯皮,就是在写 Bug。虽然这是一个梗,但也可以看出,程序员的日常一定绕不开 Bug。而花更少的时间修复软件中的 Bug,且不引入新…

第4章 Express路由的深入理解(二)

4 路由分组 路由分组用于将相关的路由组织在一起,使代码更具模块化和可维护性。可以通过使用 express.Router 创建路由组。 示例: const express require(express); const app express(); const apiRouter express.Router(); const userRouter ex…

【青书学堂】2024年第一学期 保险理论与实务(高起专) 作业

【青书学堂】2024年第一学期 保险理论与实务(高起专) 作业 为了方便日后复习,青书学堂成人大专试题整理。 若有未整理的课程,请私信我补充,欢迎爱学习的同学们收藏点赞关注!文章内容仅限学习使用!!&#xf…

debian 实现离线批量安装软件包

前言 实现在线缓冲需要的软件和对应依赖的包,离线进行安装 ,用于软件封装。 测试下载一个gcc和依赖环境,关闭默认在线源,测试离线安装gcc和依赖环境 兼容 debian ubuntu/test 测试下载安装包到目录 vim /repo_download.sh #!…

每日练习,不要放弃

目录 题目1.下面叙述错误的是 ( )2.java如何返回request范围内存在的对象?3.以下代码将打印出4.下列类定义中哪些是合法的抽象类的定义?()5.以下代码段执行后的输出结果为6.以下代码运行输出的是总结 题目 选自牛客网 1.下面叙述…

几何相关计算

目录 一、判断两个矩形是否相交 二、判断两条线段是否相交 三、判断点是否在多边形内 四、垂足计算 五、贝塞尔曲线 六、判断多边形顺时针还是逆时针 七、判断凹多边形 一、判断两个矩形是否相交 当矩形1的最大值比矩形2的最小值都小,那矩形1和矩形2一定不相…

ollama + fastgpt 搭建免费本地知识库

目录 1、ollama ollama的一些操作命令: 使用的方式: 2、fastgpt 快速部署: 修改配置: config.json: docker-compose.yml: 运行fastgpt: 访问OneApi: 添加令牌和渠道: 登陆fastgpt,创建知识库和应用 3、总结: 附录: 1. 11434是ollama的端口: 2. m3e 测…

SCI成稿丨计算机结合,中三区

Web服务器在慢速DDoS攻xxx改进研究互联网技术下基于xxx智能化交互空间艺术研究智慧城市视角企业经济发展中节xxxxx无线网络遥感图像xxx设计和规划中的应用分析基于智能物联网的生态养老控制系统与xxx展基于心理行为大数据分类算法的心理xxxxxxxxxx终端技术对消费者行为分析及客…

使用llama.cpp量化模型

文章目录 概要整体实验流程技术细节小结 概要 大模型量化是指在保持模型性能尽可能不变的情况下,通过减少模型参数的位数来降低模型的计算和存储成本。本次实验环境为魔搭社区提供的免费GPU环境(24G),使用Llama.cpp进行4bit量化可…

go 语言实现快速排序

快速排序 - go 一、思路二、步骤及图解三、代码实现四、复杂度分析 一、思路 快速排序是一种分治策略的排序算法,关键过程是对数组进行划分。选择一个基准值(pivot element),围绕着这个基准值划分子数组,对子数组递归调…

CyberVadis认证流程

1. 评估现有安全实践:组织需要对其现有的安全实践进行全面评估,包括安全策略、技术架构、人员安全意识等。 2. 确定目标:根据组织的需求和目标,确定需要改进的领域和优先级。 3. 制定计划:制定详细的认证计划&#x…

在 Windows 上开发.NET MAUI 应用_2.生成你的第一个应用

先决条件 Visual Studio 2022 17.8 或更高版本,并安装了 .NET Multi-platform App UI 工作负载。 可参考上一篇文章:http://t.csdnimg.cn/n38Yy 创建应用 1.启动 Visual Studio 2022。 在开始窗口中,单击“创建新项目”以创建新项目&#…

美式键盘 QWERTY 布局的来历

注:机翻,未校对。 The QWERTY Keyboard Is Tech’s Biggest Unsolved Mystery QWERTY 键盘是科技界最大的未解之谜 It’s on your computer keyboard and your smartphone screen: QWERTY, the first six letters of the top row of the standard keybo…

黑马头条Day02-app端文章查看,静态化freemarker

学习内容: 一、app端文章列表 1. 需求分析 文章的布局展示 2. 导入文章数据库 可以使用IDEA的数据库连接工具执行SQL脚本 3. 表结构分析 ap_article文章基本信息表 ap_article_config文章配置表 ap_article_content文章内容表 把课前资料里提供的实体类复制到mod…

转移C盘中的conda环境(包括.condarc文件修改,environment.txt文件修改,conda报错)

conda环境一般是默认安装到C盘的,若建立多个虚拟环境,时间长了,容易让本不富裕的C盘更加雪上加霜,下面给出将conda环境从C盘转移到D盘的方法。 目录 电脑软硬件转移方法查看当前conda目录转移操作第一步:.condarc文件修…

vmware虚拟机中,Centos安装Docker,解决国内无法访问

背景 本文主要解决了centos 的yum源 无法更新 和 docker的 源 国内无法访问的问题。 本文环境:windows宿主机装了vmware虚拟机,虚拟机中安装了Centos,centos内装docker。其实可以直接在window装docker desktop for windows,但…

ns3-gym入门(三):在opengym基础上实现一个小小的demo

因为官方给的"opengym""opengym-2"这两个例子都很简单,所以自己改了一个demo,把reward-action-state相互影响的关系表现出来 一、准备工作 在ns3.35/scratch目录下创建一个文件夹: (后续的运行指令后面都需要…