Java并发编程:全面解析锁策略、CAS与synchronized优化机制
一、六种锁策略场景化解析
1. 乐观锁 vs 悲观锁:图书馆借书的两种策略
核心差异:对资源是否会被抢占的预期不同。
- 乐观锁(假设冲突概率低)
→ 行为:直接去书架上拿书(围绕加锁要做的工作更少)。
→ 风险:可能发现书已被借走(需要重试)。
// 伪代码实现:类似检查版本号
if (当前书未被借) {借书成功;
} else {重新查询;
}
- 悲观锁(假设冲突概率高)
→ 行为:先预定书籍再取书(围绕加锁要做的工作更多)。
→ 保障:确保拿到书时没人争抢。
// 伪代码实现:类似直接加锁
lock(书籍);
借书操作;
unlock(书籍);
2. 轻量级锁 vs 重量级锁:开锁的两种方式
对比维度 | 轻量级锁(密码锁) | 重量级锁(管理员钥匙) |
---|---|---|
开锁速度 | 快(直接输入密码) | 慢(需找管理员申请) |
适用场景 | 短暂使用(如储物柜) | 长期占用(如保险箱) |
资源消耗 | 低(自行操作) | 高(依赖第三方) |
3. 自旋锁 vs 挂起等待锁:等电梯的两种策略
- 自旋锁:属于乐观锁/轻量级锁的一种典型表现。会忙等:等待过程中不会释放cpu资源,一旦锁释放就立即有机会拿到锁。
- 挂起等待锁:属于悲观锁/重量级锁的一种典型表现。不忙等:让出了cpu资源,锁释放后不确定什么时候去拿锁。
4. 公平锁 vs 非公平锁:排队的两种规则
- 公平锁:像银行叫号机,先到先得(需要额外的操作,引入队列时需要记录每个加锁的顺序)。
- 非公平锁:像地铁抢座位,谁快谁得(不需要额外操作,概率均等的让线程去占用锁)。
5. 可重入锁 vs 不可重入锁
核心差异:同一线程能否重复获取同一把锁。
类型 | 行为表现 | 代码示例 | 结果 |
---|---|---|---|
不可重入锁 | 同一线程重复加锁会死锁 | lock(); lock(); | 永久阻塞 |
可重入锁 | 允许同一线程多次加锁 | synchronized void a() { b(); } | 正常执行 |
synchronized void b() {} |
可重入锁三要素:
- 记录持有线程:标记当前锁的归属者。
- 身份验证:新请求的线程需匹配持有者。
- 计时器管理:
- 加锁时
+1
,解锁时-1
。 - 归零时真正释放锁。
- 加锁时
6. 读写锁:图书馆的管理规划
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();// 读者线程
rwLock.readLock().lock(); // 多个读者可同时进入
try {// 读操作
} finally {rwLock.readLock().unlock();
}// 写者线程
rwLock.writeLock().lock(); // 只允许一个写者进入
try {// 写操作
} finally {rwLock.writeLock().unlock();
}
二、synchronized锁升级过程详解
状态流转示意图(该过程不可逆)
各阶段特征
- 偏向锁(占座模式)
- 第一个线程来时做个标记(类似在座位上放本书)。
- 没有真实加锁开销,延迟真正的锁操作。
- 轻量级锁(智能转圈)
- 自适应自旋:JVM动态判断转圈次数(类似智能交通信号灯)。
- 若最近频繁抢到锁 → 允许多转几圈。
- 若多次失败 → 快速放弃转圈。
- 高效场景:适合抢锁时间 < 线程切换时间(约1μs)。
- 重量级锁(系统调度)
- 管理员介入:操作系统维护阻塞队列。
- 释放CPU:线程挂起不消耗CPU资源。
- 恢复延迟:唤醒线程需上下文切换(约10-20μs)。
关键机制图解
三、编译器优化策略
1. 锁消除:去掉多余的锁
public String concat(String s1, String s2) {Object lock = new Object(); // 局部对象不可能被共享synchronized(lock) { // 被编译器优化删除return s1 + s2;}
}
2. 锁粗化:合并相邻的锁
a. 锁粒度定义
锁粒度:指 synchronized
代码块内包含的代码量。
- 细粒度锁:代码量少,加锁范围小(如只包裹一行代码)。
- 粗粒度锁:代码量大,加锁范围广(如包裹整个方法)。
// 细粒度锁示例(不推荐)
public void process() {synchronized(this) { step1(); } // 频繁加解锁// 其他代码...synchronized(this) { step2(); }
}// 粗粒度锁示例(推荐)
public void process() {synchronized(this) { // 合并为单次加锁step1();// 其他代码...step2();}
}
b. 锁粗化(Lock Coarsening)工作原理
优化触发条件:
- 检测到连续相邻的同步块。
- 锁对象相同且无中间非同步代码。
- JIT编译器判定合并后不会显著增加竞争概率。
四、CAS机制详解
1. 核心原理:自动售货机式操作
比喻说明:
CAS操作如同使用自动售货机购买商品:
- 查看标价(读取内存值)
- 投入硬币(准备新值)
- 校验标价(比较内存值)
- 出货取货(原子性更新)
说明:alt
关键字在此处表示条件分支,相当于if
。
2. 硬件级原子性保障
; x86架构实现(CMPXCHG指令)
lock cmpxchg [mem], new_val
; lock前缀锁定总线,保证多核环境原子性
; 比较并交换:若[mem]==EAX寄存器值,则[mem]=new_val
3. CAS具体使用场景
实现原子类
private static AtomicInteger count = new AtomicInteger(0);void increment() {int oldVal, newVal;do {oldVal = count.get(); // ① 读取当前值newVal = oldVal + 1; // ② 计算新值} while (!count.compareAndSet(oldVal, newVal)); // ③ CAS更新
}// 线程安全原理:
// 假设线程A和B同时执行到③:
// - A先执行CAS成功,将0→1
// - B执行CAS时发现当前值≠oldVal(0),循环重试
实现自旋锁
public class SpinLock {private AtomicBoolean locked = new AtomicBoolean(false);// 获取锁public void lock() {while (!locked.compareAndSet(false, true)) { // CAS自旋Thread.yield(); // 让出CPU时间片避免过度消耗}}// 释放锁public void unlock() {locked.set(false);}
}
运行场景分析:
线程行为 | 锁状态变化 | 结果 |
---|---|---|
线程A获取锁 | locked: false → true | 成功,进入临界区 |
线程B尝试获取锁 | 检测到 locked = true | 自旋等待 |
线程A释放锁 | locked: true → false | 线程B CAS成功 |
4. ABA问题深度剖析:重复转账漏洞
场景描述:
张三的银行卡余额为1000元,当他尝试向他人转账500元时,由于网络延迟连续触发了两次转账请求(线程1和线程2)。与此同时,李四向张三账户转入500元(线程3),三个线程的交错执行将导致以下危险操作流:
问题本质:
- 值回退欺骗:CAS机制仅检查当前值是否等于预期值(1000元),无法感知中间发生了
1000→500→1000
的隐形状态变化。 - 资金损失:最终账户余额为500元(正确应为1000-500+500=1000元),张三实际被重复扣款1000元。
版本号解决方案:
通过版本号递增标记数据状态变化,即使值相同也能识别中间修改。
// 账户状态(版本号 + 余额)
AtomicStampedReference<Integer> account = new AtomicStampedReference<>(1000, 0); // 初始值1000元,版本0void transfer(int amount) {int[] stampHolder = new int[1];int oldValue = account.get(stampHolder); // 同时获取值和版本号int newValue = oldValue - amount;// 核心逻辑(适配为Java标准API)if (!account.compareAndSet(oldValue, // 期望值newValue, // 新值stampHolder[0], // 期望版本号stampHolder[0] + 1 // 新版本号(必须递增))) {System.out.println("转账失败:数据已被修改");} else {System.out.println("转账成功");}
}
关键机制拆解:
- 版本号必须递增
stampHolder[0] + 1 // 新版本号必须 > 旧版本号
- 不可逆性:版本号只能增加(类似流水号),确保状态变化的唯一标识。
- 防伪造:阻止恶意或错误的状态回滚(如黑客尝试恢复旧数据)。
- 原子性双重检查
compareAndSet(oldValue, newValue, oldVersion, newVersion)
- 同时校验:值是否变化 + 版本号是否匹配。
- 操作原子性:整个检查-更新过程不可分割。
结果: - 线程1的转账操作因版本号不匹配被拒绝。
- 最终余额正确为1000元(500转出 + 500转入)。
五、总结
本文系统解析Java并发编程核心机制:
- 六大锁策略:涵盖乐观锁与悲观锁、轻量级锁与重量级锁、自旋锁与挂起等待锁、公平锁与非公平锁、可重入锁、读写锁的适用场景及实现原理。
- synchronized优化:通过偏向锁→轻量级锁→重量级锁的升级过程实现性能自适应。
- 编译器优化:锁消除与锁粗化技术减少不必要的同步开销。
- CAS机制:详解原子操作原理、自旋锁实现,以及ABA问题的版本号解决方案。
结语
并发世界如同繁忙的十字路口,锁策略是交通信号灯,CAS是智能感应器,而开发者就是城市交通规划师。只有深刻理解每项机制的设计哲学,才能让数据流如同车流般高效畅通——既不会因过度控制导致拥堵,也不会因管理松散引发事故。记住:最好的并发程序不是最快的那一个,而是在正确性与性能间找到最优平衡的那一个。
相关文章:

Java并发编程:全面解析锁策略、CAS与synchronized优化机制
一、六种锁策略场景化解析 1. 乐观锁 vs 悲观锁:图书馆借书的两种策略 核心差异:对资源是否会被抢占的预期不同。 乐观锁(假设冲突概率低) → 行为:直接去书架上拿书(围绕加锁要做的工作更少)…...

2025第三届黄河流域网络安全技能挑战赛--Crypto--WriteUp
2025第三届黄河流域网络安全技能挑战赛–Crypto–WriteUp Crypto sandwitch task from Crypto.Util.number import * import gmpy2 flag bflag{fake_flag} assert len(flag) 39 p getPrime(512) q getPrime(512) n p * q e 0x3 pad1 beasy_problem pad2 bHow_to_so…...

[爬虫知识] IP代理
相关实战案例:[爬虫实战] 代理爬取:小白也能看懂怎么用代理 相关爬虫专栏:JS逆向爬虫实战 爬虫知识点合集 爬虫实战案例 引言:爬虫与IP封锁的攻防战 对网络爬虫而言,遇到的一个较棘手的问题就是封IP:请…...

6个月Python学习计划 Day 1 - Python 基础入门 开发环境搭建
6个月Python学习计划:从入门到AI实战(前端开发者进阶指南) 🎯 今日目标 理解 Python 的背景和用途安装 Python 开发环境熟悉基本语法:变量、数据类型、打印输出动手编写第一个 Python 程序 🧠 学习内容详…...

GraphPad Prism工作表的基本操作
《2025新书现货 GraphPad Prism图表可视化与统计数据分析(视频教学版)雍杨 康巧昆 清华大学出版社教材书籍 9787302686460 GraphPadPrism图表可视化 无规格》【摘要 书评 试读】- 京东图书 GraphPad Prism中包含5种工作表,每种工作表的基本操…...
Maven插件之docker-maven-plugin
介绍 在持续集成过程中,项目工程一般使用 Maven 编译打包,然后生成镜像,通过镜像上线,能够大大提供上线效率,同时能够快速动态扩容,快速回滚,着实很方便。docker-maven-plugin 插件就是为了实现…...

成年后还能学习多少知识,由大脑的这个数量决定
撰文|Anne Trafton 编译|郑添惺 审校|clefable 麻省理工学院(MIT)的一些神经科学家发现,成年的大脑中含有数百万个“静默突触”(silent synapses)。它们是神经元之间未成熟的神经突…...
Flask 会话管理:从原理到实战,深度解析 session 机制
1、Flask中session 的实现原理:服务器与客户端的协作 HTTP 协议是无状态的——服务器无法区分两次请求是否来自同一用户。这意味着,用户登录后跳转到其他页面时,服务器会“忘记”用户身份。 为解决这一问题,Web 开发中引入了会话…...

MySQL连接错误解决方案:Can‘t connect to MySQL server on ‘localhost‘ (10038)
错误描述 当您尝试连接MySQL数据库时,可能会遇到以下错误提示: 这个错误表明客户端无法连接到本地MySQL服务器。 可能的原因 MySQL服务未启动 MySQL配置问题 防火墙或安全软件阻止连接 端口被占用或未正确配置 网络连接问题 解决方案 方法一&am…...
【跨端框架检测】使用adb logcat检测Android APP使用的跨端框架方法总结
目录 Weex 跨端框架使用了uni-app的情况区分使用了uni-app还是Weex 判断使用了Xamarin判断使用了KMM框架判断使用了 Ionic 框架判断使用了Cordova框架判断使用了Capacitor 框架使用了React Native框架使用了QT框架使用了Cocos框架使用了Electron 框架使用了flutter 框架使用…...
lua脚本实战—— Redis并发原子性陷阱
需求分析 对于内容类网站,比如用户浏览题目的答案,需要先登录才能追溯,那么可以统计用户访问频率来限制数据的爬取。 可采用分级反爬虫策略,先告警、再采取强制措施: 如果每分钟超过 10 道题,给管理员发…...
【MySQL】第10节|MySQL全局优化与Mysql 8.0新增特性详解
全局优化 mysql server参数 1. max_connections(最大连接数) 含义:MySQL 服务允许的最大并发连接数(包括正在使用和空闲的连接)。超过此限制时,新连接会被拒绝(报错 Too many connections&am…...

CSS相关知识
1.清除浮动的方法 2.定位 静态定位相当于标准流 相对定位不脱离文档流,仍然占据原来的位置(最频繁的作用是给绝对定位当爹) 绝对定位脱离文档标准流,不再占有原来位置 3.BFC 1. 解决浮动元素导致的父容器高度塌陷 2. 阻止相邻元…...

AI扫描王APP:高效便捷的手机扫描工具,让生活更智能
AI扫描王APP是一款功能强大的手机扫描软件,专为追求高效、便捷的用户设计。它不仅支持文字提取和扫描翻译,还能进行测量,满足用户在不同场景下的需求。无论是办公、学习还是日常使用,AI扫描王都能帮助你快速完成任务,节…...

《仿盒马》app开发技术分享-- 原生地图展示(端云一体)
开发准备 上一节我们实现了获取当前用户的位置,并且成功的拿到了经纬度,这一节我们就要根据拿到的经纬度,结合我们其他的知识点来实现地图的展示。 功能分析 地图的展示,我们需要在管理中心先给我们对应的应用开启地图api功能&…...
Linux 操作文本文件列数据的常用命令
文章目录 Linux 操作文本文件列数据的常用命令基本列处理命令高级列处理列数据转换和排序列数据统计和分析 Linux 操作文本文件列数据的常用命令 Linux 提供了多种强大的命令来处理文本文件中的列数据,以下是一些最常用的命令和工具: 基本列处理命令 c…...

IP、子网掩码、默认网关、DNS
IP、子网掩码、默认网关、DNS 1. 概述1.1 windows配置处 2.IP 地址(Internet Protocol Address)2.1 公网ip2.2 内网ip2.3 🌐 公网 IP 与内网 IP 的关系(NAT) 3. 子网掩码(Subnet Mask)4. 默认网…...

华为OD机试真题——字符串加密 (2025B卷:100分)Java/python/JavaScript/C/C++/GO最佳实现
2025 B卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…...

角度回归——八参数检测四边形Gliding Vertex
文章目录 一、介绍(一)五参数检测方法( 基于角度)(二)八参数检测方法(point-based)的边界 二、方案分析(一)问题定义(二)方案…...
JVM 高质量面试题
📌 文章目录 一、JVM 内存结构与运行时模型1. JVM 内存结构分区及作用2. 栈帧结构及方法调用链维护3. 逃逸分析及其对对象分配策略的影响4. TLAB 的作用及提升对象创建效率的机制 二、垃圾回收器与 GC 调优1. CMS 与 G1 垃圾收集器的设计区别及适用场景2. Full GC 频…...

AI助力,制作视频裁剪软件
1. 视频裁剪软件套路多 最近再做一些测试,经常需要录屏什么的,有时候录制的时长视频,需要裁剪,比如去掉开头一些帧或者结尾的一些帧,就想保留关键点。但是网上下的一些软件,打开一用都是要付费的。所以想着…...
SQL注入基础
普通sql注入:后台能提供有价值的错误信息,显示在页面 手动注入 1. 寻找sql注入点 get注入 ?idxx url后加测试是否存在注入漏洞,报错则存在 post注入 把参数封装…...
使用 A2A Python SDK 实现 CurrencyAgent
谷歌官方的a2a-python SDK最近频繁的更新,我们的教程也需要跟着更新,这篇文章,我们通过 a2a-python sdk的 0.2.3 版本,实现一个简单的CurrencyAgent。 https://a2aprotocol.ai/blog/a2a-sdk-currency-agent-tutorial-zh 目录 源码准备详细过程 创建项目创建虚拟环境添加依…...
qt浏览文件支持惯性
#include <QApplication> #include <QListWidget> #include <QScroller> #include <QScrollerProperties>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建列表控件并添加示例项QListWidget listWidget;for (int i 0; i <…...
Python类的力量:第六篇:设计模式——Python面向对象编程的“架构蓝图”
文章目录 前言:从“代码堆砌”到“模式复用”的思维跃迁 一、创建型模式:对象创建的“智能工厂”1. 单例模式(Singleton):全局唯一的“资源管家”2. 工厂模式(Factory):对象创建的“…...

[实战]用户系统-2-完善登录和校验以及VIP
这里写目录标题 完善登录和校验新建lib-auth创建配置引入配置和JWT完善登录基本登录单点登录多点登录校验和拦截编写守卫编写装饰器使用完善VIP修改mysql模型编写vip守卫代码进度完善登录和校验 之前我们模拟过用户的登录,本节将实现token的生成,校验,redis做黑名单。我们需…...
负载均衡笔记
并发数—同时服务的调用方的数量 吞吐量—单位时间内,能接受和返回的数据请求量 TPS。 Transaction事务 QPS。Query 请求/查询 优化点: 减少并发数—防止并非过高 低级—限流—可用的用户少了?! 多开几个口—分流 DNS 解析域…...

印度语言指令驱动的无人机导航!UAV-VLN:端到端视觉语言导航助力无人机自主飞行
作者:Pranav Saxena, Nishant Raghuvanshi and Neena Goveas单位:比尔拉理工学院(戈瓦校区)论文标题:UAV-VLN: End-to-End Vision Language guided Navigation for UAVs论文链接:https://arxiv.org/pdf/250…...

mysql都有哪些锁?
MySQL中的锁机制是确保数据库并发操作正确性和一致性的重要组成部分,根据锁的粒度、用途和特性,可以分为多种类型。以下是MySQL中常见的锁及其详细说明: 一、按锁的粒度划分 行级锁(Row-level Locks) 描述:…...
解锁未来AI:使用DACA模式和Agentic技术提高开发效率
学习Agentic AI:Dapr Agentic Cloud Ascent (DACA)设计模式的应用与演进 背景介绍 近年来,Agentic AI(代理型人工智能)的概念在学术界和产业界掀起了一阵热潮。Agentic AI指的是能够自主感知、决策和行动的智能体系统,它们不仅改变了我们与技术互动的方式,也为行业发展…...