【回顾一下AQS知识,关于公平锁与非公平锁】

文章目录

    • 一.什么是AQS
    • 二.公平锁和非公平锁实现
    • 三.公平锁和非公平锁的区别
    • 四.小结

一.什么是AQS

AQS,全称 AbstractQueuedSynchronizer,是 Java 中用于构建锁和同步器的一个基础框架类,位于 java.util.concurrent.locks 包中。AQS 通过一个先进先出的(FIFO)等待队列来管理线程之间的同步,能够简化自定义同步器的开发。

AQS 的核心思想是通过一个整型状态变量(state)表示共享资源的状态,来控制线程的获取与释放。
当state>0时表示已经获取了锁,
当state = 0时表示释放了锁,在实现重入锁时,
state > 1 通常表示当前线程已经多次获取了同一个锁,即锁的重入次数。
利用一个 FIFO 的双向链表来管理被阻塞的线程,当一个线程试图获取锁时,如果锁被占用,则该线程会被加入到等待队列中,当锁被释放时,会按照先进先出的顺序唤醒队列中的下一个线程,以重新尝试获取锁。

AQS 支持独占模式与共享模式
独占模式(exclusive):一个线程独占资源,其他线程必须等待。例如 ReentrantLock 就是这种模式。
共享模式(shared):多个线程可以同时访问资源,同一时刻可以有多个线程获取同步状态。例如 CountDownLatch 使用共享模式。

如图所示:
在这里插入图片描述

二.公平锁和非公平锁实现

这里只分析ReentrantLock中公平锁和非公平锁的源码实现,其余暂不做拓展了。

瞅瞅源码:

public class ReentrantLock implements Lock, java.io.Serializable {// ReentrantLock的构造方法,传入布尔值可以构造公平锁对象 还是 非公平锁对象public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();}// ReentrantLock的加锁方法public void lock() {sync.lock();}// 成员变量Sync锁对象private final Sync sync;abstract static class Sync extends AbstractQueuedSynchronizer {abstract void lock();/*** 非公平锁的尝试去获取锁方法*/final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();// 拿到同步状态,如果资源刚好是空闲的情况下:不管队列里面有没有线程在排队,直接来一次CAS抢锁操作,抢到就执行if (c == 0) {if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}// 如果占有锁的线程就是当前线程(及锁重入逻辑)else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");// 记录锁的重入次数setState(nextc);return true;}return false;}
}/*** 非公平锁,继承这个抽象静态内部类Sync*/static final class NonfairSync extends Sync {final void lock() {// cas加一次锁if (compareAndSetState(0, 1))//设置当前为独占访问的线程setExclusiveOwnerThread(Thread.currentThread());else// cas没抢到锁则执行acquire方法,这个方法来自Sync->AbstractQueuedSynchronizer的acquire()方法acquire(1);}// 非公平锁子类实现尝试去获取锁方法--重写父类的tryAcquire方法protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}}/*** 公平锁,同样继承这个抽象静态内部类Sync*/static final class FairSync extends Sync {final void lock() {acquire(1);}/*** 公平锁子类实现尝试去获取锁方法--重写父类的tryAcquire方法*/protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();// 如果共享资源状态是空闲if (c == 0) {// hasQueuedPredecessors方法来自Sync->AbstractQueuedSynchronizer的hasQueuedPredecessors()方法,注意⚠️这里是个短路与,如果头节点下一个节点就是当前线程,即没有前驱节点的情况下,进行一次CAS抢锁操作,成功则占有if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}}

AQS里面的相关方法:

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer{/*** Node 类主要用于管理线程的排队等待信息,AQS 中的等待队列是一个双向链表,这些节点串联成队列,表示线程在获取锁或者其他同步资源时的排队情况。* Node 保存了线程的状态、排队信息以及对前驱和后继节点的引用。
*/
static final class Node {// 共享模式的标志节点:SHARED, 用于标识当前节点是以 共享模式 进行同步操作(例如:CountDownLatch、Semaphore)。static final Node SHARED = new Node(); // 独占模式的标志节点:EXCLUSIVE,用于标识当前节点是以 独占模式 进行同步操作(例如:ReentrantLock)。static final Node EXCLUSIVE = null;     // 线程被取消状态:线程在等待过程中被中断或超时,取消状态的节点不会再参与队列调度。static final int CANCELLED = 1;// 后继线程需要被唤醒状态: 当前节点释放锁或者资源后,应该唤醒它的后继节点。static final int SIGNAL = -1;// 线程正在等待条件队列:表示当前节点正在等待某个条件(用于 Condition 的实现)。当其他线程调用 signal() 时,处于该状态的节点会从条件队列转移到同步队列中。static final int CONDITION = -2;// 表示下一次获取共享资源时,可以进行传播唤醒其他节点。这通常在 共享模式 下使用。static final int PROPAGATE = -3;// 当前节点的等待状态volatile int waitStatus;// 前驱节点volatile Node prev;// 后继节点volatile Node next;// 当前节点的线程,也就是当前等待获取锁或者资源的线程。volatile Thread thread;//这个成员变量用于 Condition 队列中,用来保存条件等待队列中的下一个节点。与同步队列不同,Condition 是一个单向队列。Node nextWaiter;
}//....../*** 注意⚠️这是个短路与, !tryAcquire(arg):尝试去获取锁成功了,则不走后面的添加到等待队列的逻辑。*/
public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}
}// AQS里面的tryAcquire是空方法,待子类去重写的,及会调用到protected boolean tryAcquire(int arg) {throw new UnsupportedOperationException();}/*** 判断当前线程是否有前驱线程,也就是判断当前线程是否应该排队等待*/
public final boolean hasQueuedPredecessors() {Node t = tail; Node h = head;Node s;// 只要头节点的下一个节点不是当前线程所在的节点,返回 true,表示有前驱节点return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());}

从上面源码分别对公平锁、非公平锁分析。

  • 公平锁:ReentrantLock fairLock = new ReentrantLock(true);
  • fairLock.lock();
  1. lock()方法:只调用acquire(),其余不做任何事
  2. 公平锁的tryAcquire方法里面:如果共享资源状态是空闲(state==0)情况下,则看有没有前驱线程节点在排队,如果没有在排队的?CAS抢锁 :尾部排队(加入到双向链表尾部)
  • 非公平锁:ReentrantLock noFairLock = new ReentrantLock(false);
  • noFairLock.lock();
    1.lock()方法:上来就cas加一次锁,抢到则占有。
    2.在第一次没抢到,则调用非公平锁的tryAcquire方法:拿到同步状态,如果资源刚好是空闲(state==0)的情况下,不管队列里面有没有线程在排队,直接来一次CAS抢锁操作,抢到就执行。
    3.非公平锁经过前面两次如果都没抢到锁,那么也要尾部排队了(加入到双向链表尾部)

三.公平锁和非公平锁的区别

  1. 非公平锁在lock方法会CAS抢一次锁,公平锁不会;
  2. 非公平锁在tryAcquire方法里面,如果资源刚好空闲则不管队列有没有前驱节点在排队,直接抢锁;而公平锁在tryAcquire方法里面,如果资源刚好空闲则看有没有前驱节点在排队,有则排到队尾,没有则进行CAS抢锁操作;

四.小结

之前有认真学过一遍AQS这块源码,很久没看有点生疏了,写篇博客回顾一下~

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

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

相关文章

Android 15 推出新安全功能以保护敏感数据

Android 15 带来了增强的安全功能&#xff0c;可保护您的敏感健康、财务和个人数据免遭盗窃和欺诈。 它还为大屏幕设备带来了生产力改进&#xff0c;并对相机、消息和密钥等应用进行了更新。 Android 防盗保护 Google 开发并严格测试了一套全面的功能&#xff0c;以在盗窃之…

Java基础(6)

深拷贝和浅拷贝区别了解吗&#xff1f;什么是引用拷贝&#xff1f;关于深拷贝和浅拷贝区别&#xff0c;我这里先给结论&#xff1a;浅拷贝&#xff1a;浅拷贝会在堆上创建一个新的对象&#xff08;区别于引用拷贝的一点&#xff09;&#xff0c;不过&#xff0c;如果原对象内部…

java关于如何实现读取各种类型的文件核心属性方法,比如获取标题和作者、主题等;附带远程的https的地址文件读取方法;

有两种方法&#xff1a; 通过提供的现成api进行调用读取pdf文件&#xff0c;或doc、xlsx、pptx文件&#xff1b;可能商业需要付费 https://www.e-iceblue.cn/pdf_java_document_operation/set-pdf-document-properties-in-java.html Spire.PDF for Java import com.spire.pdf…

【初识数据库】

目录 一、数据库简介 1.什么是数据库 2.数据库与数据结构有啥关系 3.为什么要使用数据库 二、数据库服务器、数据库和表的关系 三、客户端与服务器的通讯方式 1.C/S架构 2.B/S架构 3.命令提示符 4.MySQL架构 一、数据库简介 1.什么是数据库 组织和保存数据的应用程序…

大模型入门到精通!大模型应用开发极简入门(含PDF)

大模型的出现正悄然改变人们的生活与工作方式&#xff0c;比如ChatGPT-4、文心一言、通义千问等语言大模型。它们已帮助很多办公室“白领”们在解决日常工作问题&#xff0c;如制定计划、撰写实施方案&#xff0c;甚至制作美化PPT等&#xff08;笔者及身边的同事在工作中还经常…

【算法】深入理解布隆过滤器

1. 什么是布隆过滤器&#xff1f; 布隆过滤器&#xff08;Bloom Filter&#xff09;是一种空间效率极高的概率型数据结构&#xff0c;用于检测某个元素是否在一个集合中。与常见的数据结构如哈希表不同&#xff0c;布隆过滤器无法删除元素&#xff0c;并且会存在一定的误判率&…

用示波器观测RC一阶电路零输入响应是否激励必须是方波信号

概述 RC一阶电路是一种简单但非常重要的电路&#xff0c;广泛应用于滤波、信号处理和时间常数分析等领域。在研究RC电路的动态特性时&#xff0c;零输入响应&#xff08;Natural Response&#xff09;是一项关键内容。本文将详细解析用示波器观测RC一阶电路零输入响应时&#…

如何实现安川MP3300运动控制器与西门子1200系列PLC进行ModbusTCP通讯

在工业自动化中&#xff0c;实现不同品牌、不同型号设备之间的通讯是确保生产流程顺畅、高效运行的关键。本文详细介绍了安川MP3300运动控制器与西门子1200系列PLC进行ModbusTCP通讯的具体方法。 一&#xff0e;软硬件需求 1.一台安川MP3300CPU301&#xff0c;其IP地址是192.…

SpringCloudAlibaba升级手册

目录 1. 版本对照 版本现状 SpringCloud与AlibabaCloud对应版本 Springboot与Elasticsearch版本对应 2. openfeign问题 问题 解决方案 3. Feign请求问题 问题 解决方法 4. Sentinel循环依赖 问题 解决方案 5. bootstrap配置文件不生效 问题 解决方案 6. Nacos的…

Codeforces Round 929 (Div. 3) F. Turtle Mission: Robot and the Earthquake

题目 题解&#xff1a; 按题解思路的代码&#xff1a; #include <bits/stdc.h>using i64 long long;void solve() {int n, m;std::cin >> n >> m;std::vector a(n, std::vector<int>(m));for (int i 0; i < n; i) {for (int j 0; j < m; j) …

STM32—SPI通讯协议

前言 由于I2C开漏外加上拉电阻的电路结构&#xff0c;使得通信线高电平的驱动能力比较弱&#xff0c;这就会号致&#xff0c;通信线由候电平变到高电平的时候&#xff0c;这个上升沿耗时比较长&#xff0c;这会限制I2C的最大通信速度&#xff0c; 所以&#xff0c;I2C的标准模…

uniapp-小程序开发0-1笔记大全

uniapp官网&#xff1a; https://uniapp.dcloud.net.cn/tutorial/syntax-js.html uniapp插件市场&#xff1a; https://ext.dcloud.net.cn/ uviewui类库&#xff1a; https://www.uviewui.com/ 柱状、扇形、仪表盘库&#xff1a; https://www.ucharts.cn/v2/#/ CSS样式&…

经纬恒润荣获2024中国汽车供应链大会创新成果奖

2024年9月24日-26日&#xff0c;2024中国汽车供应链大会暨第三届中国新能源智能网联汽车生态大会在武汉隆重举办。本届大会以“新挑战、新对策、新机遇——推动中国汽车供应链可持续发展”为主题&#xff0c;集聚政府主管领导、行业专家、汽车及零部件企业精英和主流媒体&#…

Ubuntu24.04 安装 NCAR Command Language(NCL)

目录 一般直接在Terminal中使用apt安装命令即可&#xff0c; 出现这样的问题&#xff0c; 如何解决这个问题呢&#xff1f; 一般直接在Terminal中使用apt安装命令即可&#xff0c; sudo apt install ncl-ncarg 但是&#xff0c;由于 Ubuntu 版本较新 Ubuntu 24.04&#xff…

Python OpenCV精讲系列 - 三维重建深入理解(十七)

&#x1f496;&#x1f496;⚡️⚡️专栏&#xff1a;Python OpenCV精讲⚡️⚡️&#x1f496;&#x1f496; 本专栏聚焦于Python结合OpenCV库进行计算机视觉开发的专业教程。通过系统化的课程设计&#xff0c;从基础概念入手&#xff0c;逐步深入到图像处理、特征检测、物体识…

迪杰斯特拉算法的理解

图片转载自&#xff1a;最短路径算法-迪杰斯特拉(Dijkstra)算法 - 程序小哥爱读书的文章 - 知乎 https://zhuanlan.zhihu.com/p/346558578 迪杰斯特拉&#xff0c;一个广度优先算法&#xff0c;采用了贪心策略。 第一步&#xff0c;选取顶点D&#xff0c;更新和D相连的节点C&a…

78天闭门深造1258页SpringCloud学习进阶笔记,再战蚂蚁金服

概述 作为一名程序员应该都知道SpringCloud&#xff0c;不知道就该反思一下了啊[奸笑]。所以就不有板有眼的和官方的介绍一样了&#xff0c;今天就说一下&#xff0c;我理解的SpringCloud是什么&#xff1a;我所理解的Spring Cloud就是微服务系统架构的一站式解决方案&#xf…

Java项目: 基于SpringBoot+mysql+maven+vue林业产品推荐系统(含源码+数据库+毕业论文)

一、项目简介 本项目是一套基于SpringBootmybatismavenvue林业产品推荐系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操…

算法工程师重生之第二十七天(合并区间 单调递增的数字 监控二叉树 总结)

参考文献 代码随想录 一、合并区间 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a…

Windows git 配置

需要在git-bash的目录下,配置.ssh 的配置文件 要 .ssh 目录下的配置无法使用