深入探索:AbstractQueuedSynchronizer 同步器的神秘面纱

news2025/4/16 7:03:30

文章目录

  • 🌟 一、AQS的底层实现原理
    • 🍊 1. AQS的概述
    • 🍊 2. AQS的数据结构
      • 🎉 (1) 同步状态
      • 🎉 (2) 等待队列
    • 🍊 3. AQS的锁请求和释放过程
      • 🎉 (1) 独占模式
      • 🎉 (2) 共享模式
    • 🍊 4. AQS的实战使用场景
      • 🎉 (1) ReentrantLock
      • 🎉 (2) Semaphore
      • 🎉 (3) CountDownLatch
    • 🍊 5. AQS的问题和解决方案
      • 🎉 (1) 饥饿
      • 🎉 (2) 死锁
  • 🌟 二、总结

📕我是廖志伟,一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出版社签约作者、产品软文创造者、技术文章评审老师、问卷调查设计师、个人社区创始人、开源项目贡献者。🌎跑过十五公里、徒步爬过衡山、🔥有过三个月减肥20斤的经历、是个喜欢躺平的狠人。

📘拥有多年一线研发和团队管理经验,研究过主流框架的底层源码(Spring、SpringBoot、Spring MVC、SpringCould、Mybatis、Dubbo、Zookeeper),消息中间件底层架构原理(RabbitMQ、RockerMQ、Kafka)、Redis缓存、MySQL关系型数据库、 ElasticSearch全文搜索、MongoDB非关系型数据库、Apache ShardingSphere分库分表读写分离、设计模式、领域驱动DDD、Kubernetes容器编排等。🎥有从0到1的高并发项目经验,利用弹性伸缩、负载均衡、报警任务、自启动脚本,最高压测过200台机器,有着丰富的项目调优经验。

📙经过多年在CSDN创作上千篇文章的经验积累,我已经拥有了不错的写作技巧。同时,我还与清华大学出版社签下了四本书籍的合约,并将陆续在明年出版。这些书籍包括了基础篇、进阶篇、架构篇的📌《Java项目实战—深入理解大型互联网企业通用技术》📌,以及📚《解密程序员的思维密码–沟通、演讲、思考的实践》📚。具体出版计划会根据实际情况进行调整,希望各位读者朋友能够多多支持!

以梦为马,不负韶华

希望各位读者大大多多支持用心写文章的博主,现在时代变了,信息爆炸,酒香也怕巷子深,博主真的需要大家的帮助才能在这片海洋中继续发光发热,所以,赶紧动动你的小手,点波关注❤️,点波赞👍,点波收藏⭐,甚至点波评论✍️,都是对博主最好的支持和鼓励!

  • 💂 博客主页: 我是廖志伟
  • 👉开源项目:java_wxid
  • 🌥 哔哩哔哩:我是廖志伟
  • 🎏个人社区:幕后大佬
  • 🔖个人微信号SeniorRD

💡在这个美好的时刻,本人不再啰嗦废话,现在毫不拖延地进入文章所要讨论的主题。接下来,我将为大家呈现正文内容。

CSDN
深入探索:AbstractQueuedSynchronizer 同步器的神秘面纱

🌟 一、AQS的底层实现原理

🍊 1. AQS的概述

AQS(AbstractQueuedSynchronizer)是Java提供的一个同步框架,它可以用来实现锁和其他同步工具。AQS的核心思想是共享状态的管理,它通过一个int型的volatile变量来描述同步状态,同时维护一个FIFO队列,用来存放等待线程。在AQS的实现中,同步状态的修改和FIFO队列的维护是通过CAS(Compare-And-Swap)操作实现的。

AQS提供了两种同步方式:独占模式和共享模式。独占模式指的是同一时间只有一个线程可以获取锁,其他线程需要等待独占锁的释放。共享模式指的是多个线程可以同时获取锁,这需要采用读写锁的机制来实现。

🍊 2. AQS的数据结构

在AQS中,同步状态和等待队列是最重要的数据结构。

🎉 (1) 同步状态

同步状态是AQS的核心,它用int类型的变量来描述同步状态。 AQS通过volatile关键字来保证同步状态的可见性,即当同步状态被修改后,所有的线程都可以立即看到最新的值。

同步状态通常用一个整数来表示,整数的值可以表示同步状态的各个属性。在独占模式下,可以使用0表示未锁定状态,1表示锁定状态。在共享模式下,可以使用高16位表示读锁的数量,低16位表示写锁的数量。通过这种方式可以保证同步状态的共享和独占模式可以共存。

🎉 (2) 等待队列

等待队列是AQS中的另一个重要数据结构,用来存储等待获取锁的线程。AQS通过一个FIFO队列来维护等待队列,队列中的每个元素代表一个等待线程。

在AQS的实现中,等待队列使用一个链表来实现。每个节点都包含前驱节点和后继节点,通过这些节点连接起来形成一个FIFO队列。加入队列的方法是通过自旋操作,不断尝试将当前节点加入到队列中。当同步状态的持有者释放锁时,它会尝试唤醒队列中的第一个线程。被唤醒的线程会再次尝试通过CAS操作获取锁,直到它成功获取锁为止。

🍊 3. AQS的锁请求和释放过程

在AQS中,当一个线程需要获取某个同步资源时,它会先尝试通过CAS操作修改同步状态,如果成功获取锁,则直接返回。获取锁的方法取决于同步资源的类型。

🎉 (1) 独占模式

如果是独占资源,那么只有一个线程可以获取锁,其他线程需要等待独占锁释放。此时,获取锁的方法是通过CAS操作修改同步状态,如果成功获取锁,则返回;否则被封装为Node节点,加入到FIFO队列中等待。

如果CAS操作失败,则说明当前线程没有成功获取锁,它就会被封装为一个Node节点,并加入到FIFO队列的尾部。当同步状态的持有者释放锁时,它会尝试唤醒队列中的第一个线程。被唤醒的线程会再次尝试通过CAS操作获取锁,直到它成功获取锁为止。

🎉 (2) 共享模式

如果是共享资源,多个线程可以同时获取锁,这就需要采用读写锁的机制。通过读锁可以实现多个线程同时对同一共享资源进行读操作,而写锁则是独占锁,只允许一个线程进行写操作。获取共享锁的方法是通过尝试通过CAS操作修改同步状态,并判断当前状态是否允许获取共享锁,如果成功获取锁,则返回;否则被封装为Node节点,加入到FIFO队列中等待。

当同步状态的持有者释放锁时,它会尝试唤醒队列中的第一个线程。被唤醒的线程会再次尝试通过CAS操作获取锁,直到它成功获取锁为止。如果获取锁的方式是共享锁,那么会唤醒队列中所有等待线程;如果获取锁的方式是独占锁,那么只会唤醒队列中的第一个线程。

🍊 4. AQS的实战使用场景

AQS是Java提供的一个同步框架,它可以用来实现锁和其他同步工具。AQS的应用非常广泛,常见的应用场景包括:

🎉 (1) ReentrantLock

ReentrantLock是一种可重入锁,它使用AQS来实现锁的功能。在ReentrantLock中,使用一个int变量来表示同步状态。当一个线程获取独占锁时,会将同步状态设置为1,当释放锁时,会将同步状态设置为0。

ReentrantLock支持多种锁模式,包括公平锁和非公平锁。公平锁是指所有等待锁的线程都按照先后顺序依次获取锁,非公平锁是指所有等待锁的线程可以竞争锁。

🎉 (2) Semaphore

Semaphore是一个计数信号量,它也使用AQS来实现。Semaphore的同步状态表示当前还有多少个许可证可用,当一个线程需要获取许可证时,它会尝试通过CAS操作获取许可证,如果成功获取许可证,则计数器减1,否则被封装为Node节点,加入到FIFO队列中等待。

🎉 (3) CountDownLatch

CountDownLatch是一个倒计时门闩,它也使用AQS来实现。CountDownLatch的同步状态表示还有多少个线程需要等待,当一个线程需要等待时,它会将同步状态减1,当同步状态为0时,所有线程都可以继续执行。

🍊 5. AQS的问题和解决方案

AQS在实际应用过程中可能会出现的问题主要有两个:饥饿和死锁。

🎉 (1) 饥饿

饥饿是指某个线程无法获取锁,导致一直处于等待状态,无法执行代码的情况。饥饿的原因有很多,例如锁竞争激烈、锁占用时间过长等。为了解决饥饿问题,可以采用公平锁的方式,保证所有线程都有机会获取锁,避免某个线程一直无法获取锁的情况。

🎉 (2) 死锁

死锁是指两个或多个线程互相持有对方所需的资源,无法继续执行的情况。死锁的原因通常是由于线程获取锁的顺序不当导致的。为了避免死锁,可以规定所有线程获取锁的顺序相同,例如都按照顺序1、2、3的方式获取锁,这样可以避免死锁的发生。

🌟 二、总结

总的来说,AQS是Java中一个非常重要的同步框架,它采用了一种非常高效的实现方式,通过CAS操作和等待队列的维护,实现了同步状态的共享和独占,并支持多种锁模式。AQS的应用非常广泛,可以用来实现ReentrantLock、Semaphore、CountDownLatch等同步工具。在实际使用过程中,需要注意饥饿和死锁问题,采用公平锁和规定获取锁的顺序等方式,可以有效避免这些问题的发生。

CSDN

🔔如果您需要转载或者搬运这篇文章的话,非常欢迎您私信我哦~

希望各位读者大大多多支持用心写文章的博主,现在时代变了,信息爆炸,酒香也怕巷子深,博主真的需要大家的帮助才能在这片海洋中继续发光发热,所以,赶紧动动你的小手,点波关注❤️,点波赞👍,点波收藏⭐,甚至点波评论✍️,都是对博主最好的支持和鼓励!

  • 💂 博客主页: 我是廖志伟
  • 👉开源项目:java_wxid
  • 🌥 哔哩哔哩:我是廖志伟
  • 🎏个人社区:幕后大佬
  • 🔖个人微信号SeniorRD

📥博主的人生感悟和目标

探寻内心世界,博主分享人生感悟与未来目标

  • 🍋程序开发这条路不能停,停下来容易被淘汰掉,吃不了自律的苦,就要受平庸的罪,持续的能力才能带来持续的自信。我本身是一个很普通程序员,放在人堆里,除了与生俱来的盛世美颜,就剩180的大高个了,就是我这样的一个人,默默写博文也有好多年了。
  • 📺有句老话说的好,牛逼之前都是傻逼式的坚持,希望自己可以通过大量的作品、时间的积累、个人魅力、运气、时机,可以打造属于自己的技术影响力。
  • 💥内心起伏不定,我时而激动,时而沉思。我希望自己能成为一个综合性人才,具备技术、业务和管理方面的精湛技能。我想成为产品架构路线的总设计师,团队的指挥者,技术团队的中流砥柱,企业战略和资本规划的实战专家。
  • 🎉这个目标的实现需要不懈的努力和持续的成长,但我必须努力追求。因为我知道,只有成为这样的人才,我才能在职业生涯中不断前进并为企业的发展带来真正的价值。在这个不断变化的时代,我必须随时准备好迎接挑战,不断学习和探索新的领域,才能不断地向前推进。我坚信,只要我不断努力,我一定会达到自己的目标。

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

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

相关文章

Electron 学习

Electron基本简介 如果你可以建一个网站,你就可以建一个桌面应用程序。Eletron 是一个使用 JavaScript, HTML和 CSS等Web 技术创建原生程序的框架,它负责比较难搞的部分,你只需把精力放在你的应用的核心上即可。 Electron 可以让你使用纯 Jav…

s27.linux运维面试题分享

第一章 计算机基础和Linux安装 1.冯诺依曼体系结构组成部分 计算机硬件由运算器、控制器、存储器、输入设备和输出设备五大部分组成。2.Linux哲学思想(或Liunx基本原则、思想、规则) 一切都是一个文件(包括硬件)。小型,单一用途的程序。连…

分享一个月份连续的MSSA插值的GRACE level03数据集

1. 背景介绍 我们通常使用的GRACE数据包含球谐数据和mascon数据。而不管是球谐产品还是mascon产品,都存在月份数据的缺失,如下图所示(Yi and Sneeuw, 2021)。本专栏分享了一个利用多通道奇异谱分析(MSSA&#…

PostgreSQL 插件 CREATE EXTENSION 原理

PostgreSQL 提供了丰富的数据库内核编程接口,允许开发者在不修改任何 Postgres 核心代码的情况下以插件的形式将自己的代码融入内核,扩展数据库功能。本文探究了 PostgreSQL 插件的一般源码组成,梳理插件的源码内容和实现方式;并介…

Apache Doris (四十七): Doris表结构变更-Schema变更

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录

报错解决:libcudart.so和libprotobuf.so链接库未找到

报错解决:libcudart.so和libprotobuf.so链接库未找到 libcudart.so链接库未找到原因解决方法 libprotobuf.so链接库未找到原因解决方法 此博客介绍了博主在编译软件包时遇到的两个报错,主要是libcudart和libprotobuf两个动态链接库未找到的问题&#xff…

频繁full GC排查

场景:通过prometheus去拉取通过actuator组件暴露的端点中的JVM相关指标。通过告警规则,检测线上服务出现频繁full gc。 ((jvm_gc_pause_seconds_count{action"end of major GC",cause!"Heap Dump Initiated GC"}- jvm_gc_pause_sec…

显示屏没有信号monitor no signal from device

双屏幕总是有个屏幕连接不上,显示没有信号。 环境 win11 Dell dual monitor双屏 解决方法 检查电源有没有插好,HDMI或DP线有没有插好。如果仍然出现这个情况,试着更新一下驱动。 如果还是点不亮,那么关掉亮的那个显示屏。用…

前端开发技术栈(工具篇):详细介绍npm、pnpm和cnpm分别是什么,使用方法以及之间有哪些关系

目录 npm、pnpm和cnpm分别是什么 npm pnpm cnpm NPM包管理器 使用npm管理,创建/初始化项目 修改npm镜像(npm源设置) 基本命令 安装依赖项 下载特定版本的依赖 下载开发依赖 下载全局依赖(全局安装) 升级依…

redis分布式锁的应用

redis 作为分布式锁的东西 分布式锁的应用 redis,zk,数据库这些都可以实现分布式锁 我们今天主要基于redis实现的分布式锁,而且要求性能要好 基于一个小的业务场景来说,就比如说秒杀中的减库存,防止超卖这种代码就会有并发问题,比方说3个线程…

C++动态规划算法的应用:得到 K 个半回文串的最少修改次数 原理源码测试用例

本文涉及的基础知识点 动态规划 题目 得到 K 个半回文串的最少修改次数 给你一个字符串 s 和一个整数 k ,请你将 s 分成 k 个 子字符串 ,使得每个 子字符串 变成 半回文串 需要修改的字符数目最少。 请你返回一个整数,表示需要修改的 最少…

VS Code打造Julia IDE

文章目录 运行和调试Workspace绘图选项卡代码编辑 搜索并下载Julia插件后,左侧工具栏会出现Julia的三圆图标,点进去之后分为Workspace, Documentation以及Plot navigator三个子窗。 运行和调试 打开.jl文件后,其右上角会出现一个三角形的符…

【洛谷算法题】P3954-成绩【入门1顺序结构】

👨‍💻博客主页:花无缺 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P3954-成绩【入门1顺序结构】🌏题目背景🌏题目描述&#…

【1++的Linux】之文件(三)

👍作者主页:进击的1 🤩 专栏链接:【1的Linux】 文章目录 一,磁盘结构二,磁盘的抽象结构三,文件系统四,文件的增删查改五,软硬链接六,动静态库1. **动态库和静…

Socket实现服务器搭建

一、前言: Socket上篇文章已经介绍过了 他是实现网络编程的基础 。 在服务器模型中通常都是多个客户端一个服务器端,那么服务器是如何处理多个客户端的请求? 1.顺序处理 依次处理--效率低下 2.并发处理 2.1 多线程并发(线程池…

《向量数据库》——Zilliz X Dify.AI ,快速打造知识库 AI 应用

Zilliz 大模型生态矩阵再迎新伙伴!近日,Zilliz 和 Dify.AI 达成合作,Zilliz 旗下的产品 Zilliz Cloud、Milvus 与开源 LLMOps 平台 Dify 社区版进行了深度集成。 01. Zilliz Cloud v.s. Dify Dify 作为开源的 LLMs App 技术栈,在此前已支持丰富多元的大型语言模型的接入,…

解密Java中神奇的Synchronized关键字

文章目录 🎉 定义🎉 JDK6以前🎉 偏向锁和轻量级锁📝 偏向锁📝 轻量级锁📝 自旋锁📝 重量级锁🔥 1. 加锁🔥 2. 等待🔥 3. 撤销 🎉 锁优化&#x1f…

将字符串中的数据按指定分隔符分割依次存入一维数组中 numpy.fromstring()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 将字符串中的数据 按指定分隔符分割 依次存入一维数组中 numpy.fromstring() [太阳]选择题 请问以下代码中执行语句输出结果依次是? import numpy as np str1 "1.0 2.0 3.…

力扣第55题 跳跃游戏 c++ 贪心 + 覆盖 加暴力超时参考

题目 55. 跳跃游戏 中等 相关标签 贪心 数组 动态规划 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true &…

【算法训练-动态规划 四】【子序列类型问题】连续子数组的最大和

废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!本篇Blog的主题是【动态规划】,使用【数组】这个基本的数据结构来实现,这个高频题的站点是:CodeTop,筛选条件为&…