【JAVA进阶篇教学】第十五篇:Java中AQS讲解

为了带你精通 Java AQS,我画了 40 张图,从管程模型讲起! AQS 使用 FIFO 队列实现了一个锁相关的并发器模板,可以基于这个模板来实现各种锁,包括独占锁、共享锁、信号量等。AQS 中,有一个核心状态是 waitStatus,这个代表节点的状态,决定了当前节点的后续操作,比如是否等待唤醒,是否要唤醒后继节点。AQS 基于双向队列实现了入口等待队列,基于 state 变量实现了各种并发锁,上篇文章讲了入口等待队列,而这篇文章主要讲了基于 AQS 的并发锁原理。 阅读详情

博主打算从0-1讲解下java进阶篇教学,今天教学第十五篇:Java中AQS讲解。

在Java并发编程中,AQS(AbstractQueuedSynchronizer)是一个重要的框架,用于实现同步器和锁的基础。它提供了一种灵活的方式来实现各种同步器,如ReentrantLock、Semaphore、CountDownLatch等。本文将深入探讨AQS的原理、实现方式以及如何使用它来构建自定义的同步器。

目录

一、前言

二、AQS的原理

三、AQS的使用


一、前言

在 Java 中,AQS(AbstractQueuedSynchronizer)是一个用于实现同步器的抽象类,它提供了一种通用的机制来管理共享资源的访问。AQS 的主要作用是通过维护一个同步队列来实现对共享资源的同步访问,避免了多线程访问共享资源时可能出现的竞态条件和死锁等问题。

二、AQS的原理

AQS是通过一个FIFO(先进先出)的队列来管理等待线程,实现对共享资源的访问控制。它的核心思想是将状态的管理委托给了子类,通过模板方法模式来实现同步器的具体逻辑。AQS内部维护了一个state变量表示同步状态,以及一个双向链表来存放等待线程。
AQS的主要实现包括两个部分:状态管理和线程阻塞与唤醒。

  • 状态管理:AQS通过getState()和setState(int newState)方法来管理同步状态,同时提供了compareAndSetState(int expect, int update)方法来实现原子更新状态。
  • 线程阻塞与唤醒:AQS通过enq(Node node)和addWaiter(Node mode)等方法将等待线程加入到等待队列中,通过release(int arg)和unparkSuccessor(Node node)等方法来唤醒等待线程。

AQS 的原理主要基于以下几个方面:

同步队列:AQS 依赖内部的同步队列(一个 FIFO 双向队列)来完成同步状态的管理。当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成为一个节点(Node)并将其加入同步队列,同时会阻塞当前线程。当同步状态释放时,会把首节点中的线程唤醒,使其再次尝试获取同步状态。

节点:同步队列中的节点(Node)用来保存获取同步状态失败的线程引用、等待状态以及前一个节点和后一个节点。节点的属性类型与名称以及描述如下表所示:

属性类型

名称

描述

Thread

thread

获取同步状态失败的线程

int

waitStatus

等待状态

Node

prev

前一个节点

Node

next

后一个节点

状态变量:AQS 使用两个原子状态变量来维护同步状态:

  • state:表示资源的状态,可以用于表示锁的占用情况或者其他同步状态。
  • exclusiveOwnerThread:表示当前占用锁的线程。

AQS 的实现通过维护状态变量和同步队列,确保了多线程对共享资源的访问是有序的,避免了竞态条件和死锁等问题的出现。

三、AQS的使用

下面是一个简单的 AQS 使用示例,演示了如何使用 AQS 来实现一个简单的锁:

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class MyLock extends AbstractQueuedSynchronizer {

    @Override
    protected boolean tryAcquire(int arg) {
        // 判断是否可以获取锁
        if (getState() == 0) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
        }
        return false;
    }

    @Override
    protected boolean tryRelease(int arg) {
        // 判断是否可以释放锁
        if (getState() == 1 && getExclusiveOwnerThread() == Thread.currentThread()) {
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
        return false;
    }

    public void lock() {
        acquire(1);
    }

    public void unlock() {
        release(1);
    }

    public static void main(String[] args) {
        MyLock lock = new MyLock();

        // 线程 1 获取锁
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Thread 1 获取锁成功");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
                System.out.println("Thread 1 释放锁成功");
            }
        }).start();

        // 线程 2 获取锁
        new Thread(() -> {
            lock.lock();
            try {
                System.out.println("Thread 2 获取锁成功");
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
                System.out.println("Thread 2 释放锁成功");
            }
        }).start();
    }
}

在上述示例中,我们创建了一个名为MyLock的类,它继承自AbstractQueuedSynchronizer。在MyLock类中,我们重写了tryAcquire和tryRelease方法,用于实现锁的获取和释放逻辑。
在main方法中,我们创建了一个MyLock对象,并启动了两个线程。每个线程在执行任务之前,都需要先获取锁,然后在任务执行完毕后释放锁。由于锁是互斥的,所以只有一个线程能够同时获取锁。
通过使用 AQS,我们可以方便地实现各种同步器,如锁、信号量、栅栏等。AQS 的优点是通用性强、效率高、扩展性好,可以满足不同场景下的同步需求。

点下关注,不会迷路!

Java并发编程之AQS AQS是AbstractQueueSynchronizer是缩写,其意思就是抽象队列同步器。原理就是通过一个FIFO队列维护一个state同步状态值,只需要继承该抽象类重写对应的方法便可实现一套线程同步机制。AQS抽象类在java.util.concurrent.locks包下定义。如上图所示,AQS属于一个抽象类,主要是用来构建锁结构以及同步器的一个抽象类。AQS继承了AbstractOwnableSynchronizer,其作用为设置和获取独占锁的拥有者线程方法。 阅读详情

相关推荐

《商用密码应用与安全性评估》第四章密码应用安全性评估实施要点4.1密码应用方案设计

密码应用方案设计

qq_40442137的博客 1472

Java并发-AQS及各种Lock锁的原理

 AQS是AbstractQueuedSynchronizer的简称。AQS提供了一种实现阻塞锁和一系列依赖FIFO等待队列的同步器的框架,如下图所示。AQS为一系列同步器依赖于一个单独的原子变量(state)的同步器提供了一个非常有用的基础。子类们必须定义改变state变量的protected方法,这些方法定义了state是如何被获取或释放的。鉴于此,本类中的其他方法执行所有的排队和阻塞机制。子...

phcgld1314的博客 608

MAX30102心率血氧传感器

估算AC、DC值的方法如下:找两个波谷点,两个波谷点之间有一个波峰点,两个波谷点相连成一条直线,与Y轴平行的线穿过波峰点会与两个波谷点连接成的直线相交于一点,这个点就是DC点,DC点的Y轴对应值就是直流分量,AC分量的值为波峰点到DC点之间的差值。在医院测量中常用的一种血氧采集方式,如下图所示,光电传感器和光源分别置于手指的两侧,光源穿过手指被另一侧的光电二极管接收,根据光衰减量计算血氧浓度。那么,根据上面的Beer-Lambert 定理,针对测量的具体场景,测量过程的衰减为三层穿透物质衰减量的叠加。

qq_41861711的博客 1万+

Java知识学习13(AQS详解)

JavaSE

ldy007714的博客 3523

STM32CUBEMX+STM32H750VB+LWIP+LAN8720A+FREERTOS TCP服务器、UDP数据接收发送、网线热插拔、IAR-8.32开发

STM32CUBEMX+STM32H750VB+LWIP+LAN8720A+FREERTOS TCP服务器、UDP数据接收发送、网线热插拔、IAR-8.32开发STM32H750VB使用STM32CUBEMX生成工程IAR+J-LINK调试准备工作CUBEMX生成的代码问题所在如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章U

qq_37433166的博客 5345

SpyGlass Lint脚本实战:从环境配置到报告生成的完整流程解析

本文详细解析了使用SpyGlass Lint脚本进行数字芯片设计代码质量检查的完整自动化流程。从环境配置、目录结构设计,到核心TCL脚本的编写与模块化配置,再到脚本执行、调试技巧及报告解读,提供了构建健壮、可维护自动化检查框架的实战指南。文章重点阐述了如何通过脚本实现从环境配置到报告生成的一键式操作,并探讨了与企业级CI/CD流程集成的进阶方案。

weixin_29196613的博客 439

JAVA多线程基础篇-AQS(AbstractQueuedSynchronizer)

AQS(AbstractQueuedSynchronizer)抽象队列同步器,是一种用来构建锁和同步器的框架。在JAVA,AQS是其它同步组件的基础框架(ReentrantLock、Semaphore、CountDownLatch、ReentrantReadWriteLock、SynchronusQueue等),它是JUC并发包中的核心组件。它不仅解决了在实现同步器时涉及的大量细节问题(自定义标准同步状态、FIFO同步队列等),还充分考虑了伸缩性,降低了上下文开销、提高了吞吐量。

qq_33479841的博客 3976

ArcGIS标注太乱?手把手教你用‘要素分类标注’搞定河流分级显示

本文详细介绍了如何在ArcGIS Pro中使用要素分类标注功能实现河流分级显示,解决标注混乱问题。通过数据预处理、分类标注规则定义和高级参数调优,帮助用户打造层次分明、专业清晰的水系地图,提升地图信息传达效率。

weixin_30326741的博客 474

Java开发常见面试题详解(LockSupport,AQS,Spring循环依赖,Redis)

00_前言闲聊和课程说明 教学视频 暖身面试题 Redis默认端口是多少?- 6379 link Spring官网地址 - https://spring.io 经典计算机图书看过吗? 01_字符串常量Java内部加载-上 Returns a canonical representation for the string object. A pool of strings, initially empty, is maintained privately by the class String. Whe

KISS 3万+

120、NPU的Mythic M1076:模拟存算一体NPU

这篇文章分享了作者调试Mythic M1076模拟存算一体NPU的实战经验,主要包含以下要点: 硬件设计陷阱:参考电压输入必须使用低ESR电容,普通贴片电容会导致模拟计算阵列工作异常。 核心技术原理: 采用真正的存算一体架构,将权重存储为模拟电压 使用浮栅晶体管存储权重,通过电流叠加实现乘法运算 包含108个计算单元阵列(Tile),每个256×256规模 使用注意事项: 编程模型特殊,需要依赖SDK自动映射网络层 存在6-8位有效精度限制,需用量化感知训练 功耗特性独特,静态偏置电流占主要功耗 调试手段有

m0_50546716的博客 122

【LAMMPS学习】八、基础知识(4.5)TIP5P水模型

​ 五点 TIP5P 刚性水模型通过添加两个通常无质量的附加位点 L 来扩展three-point TIP3P model,其中放置与氧原子相关的电荷。这些位点 L 位于距氧原子固定距离处,形成从 HOH 平面旋转 90 度的四面角。因此,这些位点在某种程度上近似于氧的孤对,从而改善了水结构,与four-point TIP4P model相比变得更加“四面体”。

荷塘阅色 1421

【JAVA进阶篇教学】第十一篇:Java中ReentrantLock锁讲解

博主打算从0-1讲解下篇教学,今天教学第十篇:Java中ReentrantLock锁讲解。在Java并发编程中,保证多线程环境下的数据安全是至关重要的。ReentrantLock 是Java中用于实现线程安全的一种锁机制。本篇博客将深入介绍 ReentrantLock 的原理、详细说明,并通过案例演示线程不安全情况以及如何使用 ReentrantLock 实现线程安全。

Schengshuo的博客 192

YOLO26涨点改进 | 检测头改进篇 | 利用ASFF改进YOLO26检测头,自适应空间特征融合模块,在所有的目标检测上均有大幅度的涨点效果

本文提出了一种自适应空间特征融合(ASFF)检测头YOLO26,用于解决目标检测中特征金字塔跨尺度特征不一致的问题。ASFF通过学习空间权重图,自适应地融合不同尺度的特征,抑制特征层间的冲突信息。实验表明,该方法在MSCOCO数据集上显著提升了检测精度(45FPS下AP达42.4%),且仅引入极小推理开销。ASFF模块具有可微分性、模型无关性和计算成本低等优势,能够有效改善特征尺度不变性,实现速度与精度的良好平衡。文章详细介绍了ASFF的原理、实现代码及其在YOLO模型中的集成方法。

Ai缝合怪、助力小伙伴高效发论文 553

保姆级教学带你拿下Java中的锁机制(下 )

Java并发编程中的AQS与锁机制详解 摘要:本文深入解析了Java并发编程的核心组件AQS(AbstractQueuedSynchronizer)及其在锁实现中的应用。AQS通过volatile状态变量和CLH队列实现线程同步,支持独占锁(如ReentrantLock)和共享锁(如Semaphore)。重点分析了可重入锁的实现原理,包括公平锁与非公平锁的区别:公平锁严格按队列顺序获取,非公平锁允许插队提高吞吐量。同时探讨了分段锁、锁粗化和锁消除等优化技术。文章还详细解读了Condition接口的线程协作机

xuziang13的博客 904

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

AQS如何保证锁并发安全

什么是AQS? AQS哪些过程会存在线程安全风险? AQS如何保证线程安全?

学而不思则罔 853

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

深入解析AQS:构建Java并发框架的核心原理

实际操作中发现,其内置的Java环境可以直接运行AQS演示项目,通过实时预览能清晰观察到线程排队和状态变化过程。支持独占/共享两种资源访问模式,覆盖ReentrantLock等常见组件。这种可视化方式比本地IDE调试更直观,特别适合教学演示和原理验证场景。状态值语义由子类定义(如ReentrantLock中0表示未锁定)waitStatus包含CANCELLED等四种状态标志。共享模式需考虑资源释放的传播逻辑。释放时唤醒后继节点形成链式反应。避免不必要的线程唤醒。

CitrineLion90的博客 422

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Doug Lea大作AQS,掌握了可以横着走

❝推荐:以免费实战教学为目的开源系统bcMall,欢迎star:https://github.com/xjjdog/bcMall❞如果你想深入研究Java并发的话,那么AQS一定是绕不开的...

小姐姐味道 909

不看绝对血亏!java开发视频教学

1 什么是自旋锁和互斥锁? 由于CLH锁是一种自旋锁,那么我们先来看看自旋锁是什么? 自旋锁说白了也是一种互斥锁,只不过没有抢到锁的线程会一直自旋等待锁的释放,处于busy-waiting的状态,此时等待锁的线程不会进入休眠状态,而是一直忙等待浪费CPU周期。因此自旋锁适用于锁占用时间短的场合。 这里谈到了自旋锁,那么我们也顺便说下互斥锁。这里的互斥锁说的是传统意义的互斥锁,就是多个线程并发竞争锁的时候,没有抢到锁的线程会进入休眠状态即sleep-waiting,当锁被释放的时候,处于休眠状态的一个线程会再

weixin_57485542的博客 165

java实现基于事件对象实现线程同步(附带源码)

java实现基于事件对象实现线程同步(附带源码)

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 1028

Java开发常见面试题详解(LockSupport,AQS,Spring循环依赖,Redis)_3

Java开发常见面试题详解(LockSupport,AQS,Spring循环依赖,Redis)_3 总览 问题 详解 String.intern()的作用 link LeetCode的Two Sum题 link 什么是可重入锁? link 谈谈LockSupport link 谈谈AQS link Spring的AOP顺序 link Spring的循环依赖 link Redis各基本类型应用场景 link Redis分布式锁 link Redis内存配置及

weixin_44323033的博客 863
上一篇: SQL实现md5加密方法
下一篇: Android Studio安装及组件配置(SDK、JDK、Gradle)
普通网友
博客等级 码龄4年 3126粉丝 192原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值