AbstractQueuedSynchronizer之AQS

一、前置知识

        公平锁和非公平锁:
        公平锁:锁被释放以后,先申请的线程先得到锁。性能较差一些,因为公平锁为了保证时间上的绝对顺序,上下文切换更频繁
        非公平锁:锁被释放以后,后申请的线程可能会先获取到锁,是随机或者按照其他优先级排序的。性能更好,但可能会导致某些线程永远无法获取到锁

        可重入锁:
        也叫做递归锁,指的是线程可以再次获取自己的内部锁,比如一个线程获取到了对象锁,此时这个对象锁还没有释放,当其想再次获取这个对象锁的时候还是可以获取的,如果不可重入的话,会导致死锁。

        
        自旋思想:
        当线程请求锁时,如果锁已经被其他线程持有,那么该线程会不断地重试获取锁,而不是被挂起等待,这种不断尝试获取锁的行为称为自旋

        LockSupport:
        一个工具类,用于线程的阻塞和唤醒操作,类似于wait()和notify()方法,但是更加灵活和可控提供了park()和unpark()两个静态方法用于线程阻塞和唤醒操作。优点在于可以在任意时刻阻塞和唤醒线程而不需要事先获取锁或监视器对象。

        数据结构之双向链表:
        双向链表(Doubly Linked List)是一种常见的数据结构,它是由一系列结点(Node)组成的,每个结点包含三个部分:数据域、前驱指针和后继指针。其中,数据域存储结点的数据,前驱指针指向前一个结点,后继指针指向后一个结点。通过这种方式,双向链表可以实现双向遍历和插入、删除操作。

        设计模式之模板设计模式:
        模板设计模式是一种行为型设计模式,定义了一种算法的框架,并将某些步骤延迟到子类中事先,这种设计模式的主要目的是允许子类在不改变算法结构的情况下重新定义算法中的某些步骤。
        优点是能够提高代码复用性和可维护性。

二、AQS入门级别理论知识

        1、是什么?

        字面意思:抽象的队列同步器
        通常的AbstractQueuedSynchronizer 简称为 AQS。

        技术解释:
        是用来实现锁或者其他同步器组件的公共基础部分的抽象实现
        是重量级基础框架及整个JUC体系的基石,只要用于解决锁分配给”谁“的问题。
        整体就是一个抽象的FIFO队列来完成资源获取线程的排队工作,并通过一个int类变量表示持有锁的状态

        2、AQS为什么是JUC内容中最重要的基石

        和AQS有关的:

        ReentrantLock:

        CountDownLatch:

        ReentrantReadWriteLock:

        Semaphore:

        进一步理解锁和同步器的关系:
        锁,面向锁的使用者:定义了程序员和锁交互的使用层API,隐藏了实现细节,你调用即可同步器,面向锁的实现者。
        Java并发大神DoungLee,提出了统一规范并简化了锁的实现,将其抽象出来,屏蔽了同步状态管理、同步队列的管理和维护、阻塞线程排队和通知、唤醒机制等,是一切锁和同步组件实现的----公共基础部分

        3、能干嘛?

        加锁会导致阻塞------有阻塞就需要排队,实现排队必然需要队列
        抢到资源的线程直接使用处理业务,抢不到资源的必然涉及一种排队等候机制。抢占失败的线程继续去等待(类似于银行办理窗口都满了,暂时没有受理窗口的顾客只能去候客区排队等待),但等候线程仍然保留获取锁的可能且获取锁流程仍在继续(候客区的顾客也在等着叫号,轮到了再去受理窗口办理业务)
        
        既然说到了排队等候机制,那么就一定会有某种队列形成,这样的队列是什么数据结构呢?
        
如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁分配。这个机制主要用的是CLH队列的变体实现的,将暂时获取不到锁的线程加入到队列中,这个队列就是AQS同步队列的抽象表现。它将要请求共享资源的线程及自身的等待状态封装成队列的节点对象(Node),通过CAS、自旋以及LockSupport.park()的方式,维护着state变量的状态,使其达到同步的状态。

        4、小总结

        AQS同步队列的基本结构:

        内部类Node(Node类在AQS类内部)
        Node的int变量
        Node的等待状态waitState成员变量:volatile int waitStatus;
        等候区其它顾客(其它线程)的等待状态。队列中每个排队的个体就是一个Node

        Node此类的讲解:

三、AQS源码分析前置知识储备

        1、AQS内部体系架构图

        2、AQS内部体系架构----AQS自身

        AQS的int类型变量state:
        
AQS的同步状态State成员变量
       

        

        银行办理业务的受理窗口状态:
        零就是没人,自由状态可以去办理
        大于等于1,有人占用窗口,等着去

        AQS的CLH队列:
        
CLH(三个大牛的名字组成)队列为一个双向队列

        银行候客区的等待顾客

        小总结:
        有阻塞就需要排队,实现排队必然需要队列
        State变量+CLH双端队列

        3、AQS内部体系架构----内部类Node

        Node的int变量:
        Node的等待状态waitState成员变量
        

            说人话:
            等候区其他顾客(其他线程)的等待状态
            队列中每个排队的个体就是一个Node

            Node此类的讲解:
            内部结构:


            

            属性说明:

    四、AQS源码深度讲解和分析

            1、ReentrantLock的原理

            Lock接口的实现类,基本都是通过聚合了一个队列同步器的子类完成线程访问控制的

            2、从最简单的lock方法开始看看公平和非公平


    公平锁和非公平锁的lock()方法唯一的区别就在于公平锁在获取同步状态时多了一个限制条件:hasQueuedPredecessors()-----公平锁加锁时判断等待队列中是否存在有效节点的方法

            3、以非公平锁ReentrantLock()为例作为突破走起---方法lock()

            对比公平锁和非公平锁的tryAcquire()方法的实现代码,其实差异就在于非公平锁获取锁时比公平锁中少了一个判断!hasQueuedPredecessors(),hasQueuedPredecessors()中判断了是否需要排队,导致公平锁和非公平锁的差异如下:
            公平锁:公平锁讲究先来后到,线程在获取锁时,如果这个锁的等待队列中已经有线程在等待,那么当前线程就会进入到等待队列中;
            非公平锁:不管是否有等待队列,如果可以获取到锁,则立刻占有锁对象。也就是说队列的第一个排队线程苏醒后,不一定就是排头的这个线程获得锁,它还需要参加竞争锁(存在线程竞争的情况下),后来的线程可能不讲武德插队夺锁了。

            正式开始源码解读:
            
    lock():

          

            acquire():

            tryAcquire(arg):
           
     return false:继续推进条件,走下一个方法
            return true:结束

            addwaiter(Node.EXCLUSIVE):

            注意:在双向链表中,第一个节点为虚节点(也叫做哨兵节点),其实不存储任何信息,只是占位。真正的第一个有数据的节点,是从第二个节点开始的
            假如此时有线程C进入:

            acquireQueued(addWeiter(Node.EXCLUSIVE), arg)-----坐稳队列:

            

            4、unlock()

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

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

    相关文章

    内存泄漏系列专题分析之十一:高通相机CamX ION/dmabuf内存管理机制Camx ImageBuffer原理

    【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:内存泄漏系列专题分析之八:高通相机CamX内存泄漏&内存占用分析--通用ION(dmabuf)内存拆解 这一篇我们开始讲: 内存泄漏系列专题分析之十一:高通相机CamX ION/dmabuf内存管理机制Camx ImageBuf…

    《类和对象(下)》

    引言: 书接上回,如果说类和对象(上)是入门阶段,类和对象(中)是中间阶段,那么这次的类和对象(下)就可以当做类和对象的补充及收尾。 一:再探构造…

    Java MVC

    在软件开发中,MVC(Model-View-Controller)是一种常用的设计模式,它将应用程序分为三个核心部分:模型(Model)、视图(View)和控制器(Controller)。这…

    嵌入式学习笔记 - 关于单片机的位数

    通常我们经常说一个单片机是8位的,16位的,32位的,那么怎么判断一款单片机的位数是多少位呢,判断的依据是什么呢, 一 单片机的位数 单片机的位数是指单片机数据总线的宽度,也就是一次能处理的数据的位数&a…

    推荐几个常用免费的文本转语音工具

    推荐几个常用免费的文本转语音工具 在数字内容创作的时代,文本转语音(TTS)技术已经成为内容创作者的得力助手。无论是制作视频配音、有声读物、还是为网站增加语音功能,这些工具都能大幅提高创作效率。今天,我将为大家推荐几款优质的免费文本…

    Microsoft Azure DevOps针对Angular项目创建build版本的yaml

    Azure DevOps针对Angular项目创建build版本的yaml,并通过变量控制相应job的执行与否。 注意事项:代码前面的空格是通过Tab控制的而不是通过Space控制的。 yaml文件中包含一下内容: 1. 自动触发build 通过指定code branch使提交到此代码库的…

    Python Day23 学习

    继续SHAP图绘制的学习 1. SHAP特征重要性条形图 特征重要性条形图(Feature Importance Bar Plot)是 SHAP 提供的一种全局解释工具,用于展示模型中各个特征对预测结果的重要性。以下是详细解释: 图的含义 - 横轴:表示…

    .NET 8 + Angular WebSocket 高并发性能优化

    .NET 8 Angular WebSocket 高并发性能优化。 .NET 8 WebSocket 高并发性能优化 WebSocket 是一种全双工通信协议,允许客户端和服务端之间保持持久连接。在高并发场景下,优化 WebSocket 的性能至关重要。以下是针对 .NET 8 中 WebSocket 高并发性能优化…

    Ubuntu 22.04.5 LTS 基于 kubesphere 安装 cube studio

    Ubuntu 22.04.5 LTS 基于 kubesphere 安装 cube studio 前置条件 已经成功安装 kubesphere v4.3.1 参考教程: https://github.com/data-infra/cube-studio/wiki/%E5%9C%A8-kubesphere-%E4%B8%8A%E6%90%AD%E5%BB%BA-cube-studio 1. 安装基础依赖 # ubuntu安装基础依赖 apt insta…

    centos 7 安装 java 运行环境

    centos 7 安装 java 运行环境 java -version java version "1.8.0_131" Java(TM) SE Runtime Environment (build 1.8.0_131-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)java -version java version "1.8.0_144" Java(TM) …

    Linux系统管理与编程20:Apache

    兰生幽谷,不为莫服而不芳; 君子行义,不为莫知而止休。 做好网络和yum配置,用前面dns规划的www的IP进行。 #!/bin/bash #----------------------------------------------------------- # File Name: myWeb.sh # Version: 1.0 # …

    .NET 在鸿蒙系统上的适配现状

    目录 .NET 在鸿蒙系统上的适配现状 鸿蒙系统对虚拟机的限制与.NET的适配挑战 NativeAOT 在鸿蒙系统中的适配原理与实现方式 已知问题与解决方案:鸿蒙系统中的 syscall 限制 鸿蒙系统适配中的技术难点与解决方案 跨平台编译的挑战与应对策略 依赖库管理与兼容…

    kotlin JvmName注解的作用和用途

    1. JvmName 注解的作用 JvmName 是 Kotlin 提供的一个注解,用于在编译为 Java 字节码时自定义生成的类名或方法名。 作用对象: 文件级别(整个 .kt 文件)函数、属性、类等成员 主要用途: 控制 Kotlin 编译后生成的 JV…

    树莓派4 yolo 11l.pt性能优化后的版本

    树莓派4 使用 Picamera2 拍摄图像,然后通过 YOLO11l.pt 进行目标检测,并在实时视频流中显示结果。但当前的代码在运行时可能会比较卡顿,主要原因包括: picam2.capture_array() 是一个较慢的操作;YOLO 推理可能耗时较长…

    Docker私有仓库实战:官方registry镜像实战应用

    抱歉抱歉,离职后反而更忙了,拖了好久,从4月拖到现在,在学习企业级方案Harbor之前,我们先学习下官方方案registry,话不多说,详情见下文。 注意:下文省略了基本认证 TLS加密&#xff…

    MySQL 安全架构:从渗透测试到合规审计

    MySQL 安全架构:从渗透测试到合规审计 一、数据库安全的时代挑战与核心需求 在数据成为企业核心资产的今天,MySQL 面临的安全威胁日益复杂。据统计,2024 年全球数据库泄露事件中,关系型数据库占比高达 68%,其中 MySQ…

    【基础复习笔记】计算机视觉

    目录 一、计算机视觉基础 1. 卷积神经网络原理 2. 目标检测系列 二、算法与模型实现 1. 在PyTorch/TensorFlow中实现自定义损失函数或网络层的步骤是什么? 2. 如何设计一个轻量级模型用于移动端的人脸识别? 3. 描述使用过的一种注意力机制&#…

    Django 项目的 models 目录中,__init__.py 文件的作用

    在 Django 项目的models/init.py文件中,这些导入语句的主要作用是将各个模型类从不同的模块中导入到models包的命名空间中。这样做有以下几个目的: 简化导入路径 当你需要在项目的其他地方使用这些模型时,可以直接从models包导入&#xff0c…

    实现一个简单的 TCP 客户端/服务器

    注意: TCP 三次握手建立连接建立连接后,TCP 提供全双工的通信服务,也就是在同一个连接中,通信双方 可以在同一时刻同时写数据,相对的概念叫做半双工,同一个连接的同一时刻,只能由一方来写数据T…

    专业课复习笔记 9

    前言 学爽了。 为什么哈希函数的空间复杂度是 O(N) 我们实际使用的电话号码的数目是 N &#xff0c;理论上至多有 R 个电话号码&#xff0c;桶数组 bucket array 的容量是 M &#xff0c;满足条件 N < M < < R N<M<<R N<M<<R&#xff0c;因为动…