AQS源码解读

news2024/11/25 22:52:19

 retrantlock:

A、B、C3个线程,假设A线程lock()时候拿到了锁,state被A设置成了1。

  static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
        final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

 此时B和C调用lock时候就会走else,调用acquire(1);

我们可用看见这里的B和C会尝试获取锁,没有获取到就会把当前线程封装成node节点放到CLH双向队列里。让后阻断当前线程

AQS的 tryAcquire(),

实际是调用RetrantLock的非公平nonfairTryAcquire();

 

 此时 int c = getState();  c是1   并且current == getExclusiveOwnerThread()条件不成立。因为此时线程A占有锁,所以current此时是线程B 与 getExclusiveOwnerThread()是线程A,并不相等,返回false。

else if (current == getExclusiveOwnerThread()) {
    int nextc = c + acquires;
    if (nextc < 0) // overflow
        throw new Error("Maximum lock count exceeded");
    setState(nextc);
    return true;
}

上面这段代码以上是假设B来了A刚好释放了锁,此时,突然A又来抢到了锁,这个时候current就是A线程和 getExclusiveOwnerThread()也是线程A,相等。又将state设置为1,并且占用锁。

将当前线程封装成node节点放到队列里

 private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

你会发现底层调用了unsafe的接口 ,头指针主要是用于入队。

new Node()作为头节点 (第一个节点)

 

 

acquireQueued()干了一件什么事呢?

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

 

没有抢到锁就阻塞,LockSupport.park(this);线程挂起不会继续往下执行

 

compareAndSetWaitStatus(pred, ws, Node.SIGNAL);

 unlock()f释放锁;

 

 public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

 

释放锁实现:

 int c = getState() - releases; state的值此时是1,releases值也是1  所以c就变成了0,就释放了锁

 setExclusiveOwnerThread(null);设置当前占用线程为null,就是没有线程占用。

 setState(c);将state状态重新设置为0.

 

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

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

相关文章

喜欢写笔记的博主为什么要使用猿如意?

&#x1f525;&#x1f525;&#x1f525;猿如意&#x1f525;&#x1f525;&#x1f525; 喜欢写笔记的博主为什么要使用猿如意&#xff1f; markdown笔记 测 评 分 享 猿如意实战测评猿如意传送门什么是猿如意&#xff1f;猿如意使用感受markdown笔记实战测评总结猿如意传…

数据结构---红包分配算法

红包分配算法错误解法二倍均值法JAVA实现线段切割法确定每一条子线段的长度JAVA实现问题如下&#xff1a; 所有人抢到的金额之和要等于红包金额&#xff0c;不能多也不能少。每个人至少抢到1分钱。要保证红包拆分的金额尽可能分布均衡&#xff0c;不要出现两极分化太严重的情况…

【C函数】函数详解

函数前言一、函数是什么二、C语言中函数的分类&#xff08;一&#xff09;库函数1.printf类2.strcpy类3.math类4.概念5.小知识6.总结&#xff08;二&#xff09;自定义函数1.概念2.函数的组成3.例子1&#xff08;求出两个数中的最大值&#xff09;4.例子2&#xff08;交换两个整…

mac释放“其他”内存空间的解决方法

官方解释Mac设备储存空间中的“其他”数据包含这不可移除的移动资源&#xff0c;例如&#xff0c;Siri 语音、字体、词典、不可移除的日志和缓存、聚焦索引以及系统数据如钥匙串和 CloudKit 数据库、系统无法删除缓存的文件等之外&#xff0c;还包含了一些无法识别的文件。当“…

ROS2 基础概念 节点

ROS2 基础概念 节点1. Nodes2. 重映射3. 环境设置3.1. ROS_DOMAIN_ID3.2. ROS_LOCALHOST_ONLY1. Nodes 每个节点应负责单个模块用途&#xff08;例如&#xff0c;一个节点用于控制车轮电机&#xff0c;一个用于控制激光测距仪等&#xff09; 可以通过话题、服务、操作或参数向…

C++-----模板

举个例子&#xff0c;如果要你交换两个数值&#xff0c;你会怎么做呢&#xff1f; ————你肯定会说&#xff0c;那就写一个Swap交换函数吧&#xff01; 没错&#xff01;Swap函数确实可以实现交换&#xff0c;但如果我想让你同时进行不能类型的数值呢&#xff0c;比如floa…

F - Permutation Distance(去绝对值数据结构)[AtCoder Beginner Contest 283]

题目如下&#xff1a; 题目链接 题解 or 思路&#xff1a; 去掉绝对值后 有 2242 \times 2 4224 中情况 虚线括起来的是需要维护的&#xff0c;其他直接枚举就行! 对于 pi<pjp_i < p_jpi​<pj​ 的情况&#xff0c;设我们维护的式子为 xxx 那我们每次枚举查找的范围…

hadoop生产调优之HDFS—集群压测

在企业中非常关心每天从 Java 后台拉取过来的数据&#xff0c;需要多久能上传到集群&#xff1f;消费者关心多久能从 HDFS 上拉取需要的数据&#xff1f; 为了搞清楚 HDFS 的读写性能&#xff0c;生产环境上非常需要对集群进行压测。 HDFS 的读写性能主要受网络和磁盘影响比较大…

【matplotlib】3-绘制统计图形

文章目录绘制统计图形1.柱状图1.1 应用场景--定性数据的分布展示1.2 绘制原理2.条形图3.堆积图3.1 堆积柱状图3.2 堆积条形图4.分块图4.1 多数据并列柱状图4.2 多数据平行条形图5.参数探索6.堆积折线图、间断条形图和阶梯图6.1 用函数stackplot()绘制堆积折线图6.2 用函数broke…

Matlab 方位角计算

文章目录 一、简介二、实现代码三、实现效果一、简介 方位角是指从某点的正北方向起顺时针旋转到某目标点方向的水平夹角,角度范围(0~360)。如下所示: 令atn= a r c t a n ( Δ Y A B / Δ X

9. SpringMvc拦截器

1. 拦截器概念和作用 拦截器&#xff08;Interceptor&#xff09;是一种动态拦截方法调用的机制&#xff0c;在SpringMVC中动态拦截控制器方法的执行作用&#xff1a; 在指定的方法调用前后执行预先设定的代码阻止原始方法的执行总结&#xff1a;增强 核心原理&#xff1a;AOP…

[CG笔记]绘制图元:三角形

学习资料是Github的一个项目Tiny renderer or how OpenGL works: software rendering in 500 lines of code 本文对应原教程的第二课的部分内容 原教程重在思路&#xff0c;主要内容是以推导为主&#xff0c;所以这里还是记录思路和为代码做注释 知乎也有人给出了中译版&…

ARM uart stdio 的移植

一、uart stdio的移植1 1. 什么是 stdio (1) #include <stdio.h> (2) stdio&#xff1a;standard input output&#xff0c;标准输入输出 (3) 标准输入输出就是操作系统定义的默认的输入和输出通道。一般在 PC 机的情况下&#xff0c;标准输入指的是键盘&#xff0c;标…

C语言——操作符详解(下)

C语言——操作符详解&#xff08;下&#xff09;一、赋值操作符二、复合赋值符三、单目操作符单目操作符介绍四、 关系操作符五、逻辑操作符六、条件操作符七、逗号表达式八、下标引用、函数调用和结构成员8.1 [ ] 下标引用操作符8.2 ( ) 函数调用操作符8.3访问一个结构的成员一…

【Linux】Linux指令串讲

大家好&#xff0c;今天要开启一个新的专题&#xff1a;Linux 今天的内容是指令还有一些基本的Linux知识补充 由于Linux的知识很难明确写出分类&#xff0c;所以目录就不会做的特别详细完全 喜欢的小伙伴点赞收藏一下不迷路哦 目录 1.目录 2.文件 3.路径 1.目录 1.创建目录…

初识Docker:(3)Docker架构

初识Docker&#xff1a;&#xff08;3&#xff09;Docker架构镜像和容器Docker和DockerHubDocker架构总结镜像和容器 镜像&#xff08;Image&#xff09;&#xff1a;Docker将应用程序及其所需的以来、函数库、环境、配置等文件打包在一起&#xff0c;成为镜像。 容器&#x…

力扣27.移除元素(双指针算法)

题目描述&#xff1a; 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考…

编译openssl支持libcurl的https访问

如果编译时不带openssl库那么无法访问https的网页&#xff0c;从网页端什么也获取不到。 在调用post请求访问翔云OCR人脸识别时无法访问&#xff0c;而使用ssl&#xff0c;需要先在系统中安装OpenSSL。 如下图安装说明&#xff1a; 所以将原先安装的libcurl库删掉&#xff0…

MySQL事务的隔离级别

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;MySQL事务的隔离级别 ✅创作者&#xff1a;林在闪闪发光 ⏰预计时间&#xff1a;30分钟 &#x1f389;个人主页&#xff1a;林在闪闪发光的个人主页 &#x1f341;林在闪闪发光的个人社区&#xff0c;欢迎你的加入: 林在闪…

【C与数据结构】——寒假提高每日练习Day2

一共16日的练习&#xff0c;分为选择题与编程题&#xff0c;涵盖了C语言所学以及数据结构的重点&#xff0c;以及一些秋招、春招面试的高频考点&#xff0c;难度会随着天数而上升。1-8day为C语言&#xff0c;9-16day为数据结构。 &#xff08;建议在电脑客户端进行&#xff0c…