【回顾一下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;如果原对象内部…

谷歌浏览器如何展示小于12px的字

在谷歌浏览器里面&#xff0c;字体最小只能设置为12px&#xff0c;但是我们有时候需要展示更小的文字。方法如下&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" co…

【计算机科学】什么是ASCII码?

引言 在计算机技术的世界里&#xff0c;字符编码是一个至关重要的概念&#xff0c;它决定了我们如何将文本字符存储、传输和处理。ASCII码&#xff08;American Standard Code for Information Interchange&#xff0c;美国信息交换标准代码&#xff09;是字符编码中的一项基础…

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…

【洛谷】AT_abc188_c [ABC188C] ABC Tournament 的题解

【洛谷】AT_abc188_c [ABC188C] ABC Tournament 的题解 洛谷传送门 AT传送门 Vjudge传送门 题解 谔谔&#xff0c;最近月考&#xff0c;没时间写题解。现在终于有时间了qaq 通过对样例的数据分析我们可以看到。本题的考点就是一个二叉搜索树&#xff0c;因此最简单的方法…

Day31 || 122.买卖股票的最佳时机 II、55. 跳跃游戏、 45.跳跃游戏II 、1005.K次取反后最大化的数组和

122.买卖股票的最佳时机 II 题目链接&#xff1a;力扣题目链接 思路&#xff1a;因为是求虽大利润完全可以假设知道第二天涨前一天买入即可&#xff0c;就是求两天只差大于0 的和。 55. 跳跃游戏 题目链接&#xff1a;力扣题目链接 思路&#xff1a;应该从后往前循环判断&…

搜维尔科技:使用Manus Primel Xsens数据手套直接在Xsens及其插件中捕获手指数据

使用Manus Primel Xsens数据手套直接在Xsens及其插件中捕获手指数据 搜维尔科技&#xff1a;使用Manus Primel Xsens数据手套直接在Xsens及其插件中捕获手指数据

【初识数据库】

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

数据结构与算法JavaScript描述练习------第12章排序算法

1. 使用本章讨论的所有算法对字符串数据而非数字数据进行排序&#xff0c;并比较不同算法的执行 时间。这两者的结果是否一致呢&#xff1f; function CArray(numElements) { this.dataStore []; this.pos 0; this.numElements numElements; this.insert insert; this.toS…

HTTP安全么?如何更好的保护您的网站

在互联网飞速发展的今天&#xff0c;网络安全问题日益严峻。HTTP作为最常见的网络通信协议&#xff0c;虽然在传输效率方面表现优异&#xff0c;但其安全性却常常令人担忧。许多企业和个人网站在使用HTTP进行数据传输时&#xff0c;可能忽视了其中潜在的风险。那么&#xff0c;…

搜维尔科技:SenseGlove Nova 2触觉反馈手套开箱测评

SenseGlove Nova 2触觉反馈手套开箱测评 搜维尔科技&#xff1a;SenseGlove Nova 2触觉反馈手套开箱测评

react函数组件和类组件

react函数组件和类组件 函数组件会捕获render内部的差异&#xff0c;性能主要取决于代码正在进行的操作&#xff0c;函数组件和类组件区别可以忽略不计&#xff0c;但是优化策略是有不同的。 类组件 class Welcome extends React.Component {render() {return <h1>{th…

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

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

OpenCV人脸检测与识别:构建智能识别系统

在当今科技日新月异的时代&#xff0c;人脸识别技术以其独特的便利性和安全性&#xff0c;在各个领域都展现出了巨大的应用潜力。从智能手机的面部解锁&#xff0c;到机场的自动安检&#xff0c;再到商场的顾客行为分析&#xff0c;人脸识别技术无处不在。本文将深入探讨如何使…

简单认识redis - 9 布隆过滤器

布隆过滤器&#xff08;Bloom Filter&#xff09;是一种空间效率很高的随机数据结构&#xff0c;用于判断一个元素是否可能在一个集合中。 一、工作原理 1. 初始化&#xff1a; 布隆过滤器由一个位数组&#xff08;通常是一个很长的二进制数组&#xff09;和若干个哈希函数组…

【scene_manager_msgs】ROS2 自定义消息、服务的包

scene_manager_msgs 在ROS 1向ROS 2迁移的过程中&#xff0c;有些依赖项发生了变化&#xff0c;这是因为ROS 2的通信框架和工具链与ROS 1不同&#xff0c;尤其在消息、服务和动作生成方面有了一些新的方法和库。 动作库 如果你的ROS 1包依赖于actionlib或actionlib_msgs&…

拍立淘API返回值中的商品列表与详细信息解析

拍立淘&#xff08;Pailitao&#xff09;是阿里巴巴旗下的一种图像识别购物技术&#xff0c;允许用户通过拍摄商品照片来搜索相似的商品。尽管官方没有直接开放拍立淘的API给公众使用&#xff0c;但可以通过淘宝开放平台&#xff08;Taobao Open Platform&#xff09;的一些图像…

Python logging模块实现日志饶接 按照时间命名

import os import zipfile from datetime import datetime from logging.handlers import RotatingFileHandlerclass CompressedRotatingFileHandler(RotatingFileHandler):"""自定义的 RotatingFileHandler&#xff0c;支持在日志轮转时压缩旧日志文件&#xf…

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

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