当前位置: 首页 > article >正文

JAVA进阶-锁

1.悲观锁和乐观锁悲观锁在修改数据时一定有别的线程来使用一定会发生并发冲突所以在获取数据的时候会加锁。JAVA中的synchronized和lock都是悲观锁。乐观锁在修改数据时一定没有别的线程来使用所以不会添加锁。但是在更新数据的时候会查看有没有线程修改数据。比如版本号和CAS原理无锁原理实现方式悲观锁数据库层面select * from dual for update;JAVA层面synchronized、ReentrantLock 等独占锁。乐观锁数据库层面UPDATE table SET ...version version 1 where id ? and version ?还有时间戳、CAS。优点悲观锁强一致性写多场景非常安全不会出现并发覆盖问题乐观锁无锁性能极高高并发友好不会阻塞缺点悲观锁性能差容易阻塞、死锁高并发下吞吐量极低乐观锁冲突多时重试成本高业务代码要处理重试流程悲观锁上锁读取 / 修改释放锁乐观锁读取数据拿到 version业务处理更新时带上 version 做条件影响行数 0 → 冲突重试 / 报错使用场景悲观锁写多读少金融、库存扣减、订单支付等强一致场景乐观锁读多写少商品详情、点赞、统计、日志等1.1 CAS全面解析乐观锁的核心实现CAS是 Compare And Swap(比较并交换)的缩写是实现乐观锁的核心技术也是CPU层面提供的原子指令非JAVA语法可以理解为我认为内存里的值是A现在要改成B先检查内存里是不是真的是A如果是就改成B不是就不改。1.1.1 CAS核心思想3个核心值CAS 操作依赖3个关键参数1.内存地址V要操作的变量在内存中的位置。2.预期值A认为当前内存中应该有的值。3.新值B想要更新成的新值。执行逻辑一步到位的原子操作if (内存值 V 预期值 A) { 将内存值 V 改为 新值 B 返回 成功true } else { 不做任何修改 返回 失败false }关键整个“比较 交换” 是原子性的CPU保证不会被线程打断所以不需要加锁也能保证并发安全。1.1.2 CAS 通俗举例比如你和朋友同时给一个共享的计数器 count 加1 初始值 01. 读取到 count 0 预期值 A 0准备改成 1 新值 B 12.CAS检查内存中 count 是不是 0如果是 直接改成1返回成功如果已经先把 count 改成 1 检查失败返回失败 (需要重新读取最新值再重试)1.1.3 JAVA中的CAS实战JAVA 本身不能直接调用CPU指令但JDK 提供了java.util.concurrent.atomic 包封装了CAS操作最常用的是AtomicIntegerimport java.util.concurrent.atomic.AtomicInteger; public class CASDemo { public static void main(String[] args) { // 初始化值为 0 AtomicInteger count new AtomicInteger(0); // 核心 CAS 操作compareAndSet(预期值, 新值) boolean result1 count.compareAndSet(0, 1); System.out.println(第一次更新 result1); // true更新成功count1 // 再次用 0 作为预期值更新此时内存值是 1 boolean result2 count.compareAndSet(0, 2); System.out.println(第二次更新 result2); // false更新失败 // 用最新值 1 作为预期值更新 boolean result3 count.compareAndSet(1, 2); System.out.println(第三次更新 result3); // true更新成功count2 } }常用简化方法 底层还是CASAtomicInteger提供了更易用的方法 如incrementAndGet()底层都是 CAS 自旋重试// 等价于 count但线程安全CAS 自旋重试直到成功 int newCount count.incrementAndGet(); System.out.println(newCount); // 31.1.4 CAS的优点 缺点优点1.无锁不需要加 synchronized 或 Lock 避免线程阻塞和上下文切换性能极高。2.原子性 CPU 级别的原子操作比锁更轻量。3.并发友好高并发下吞吐量远高于悲观锁。缺点1.ABA问题最核心问题变量从A - B - A,CAS 检查时发现是A会误以为没被修改但实际已经被改过。解决JDK 提供 AtomicStampedReference 加版本号/时间戳类似乐观锁的版本号机制2.自旋开销如果并发冲突频繁CAS会一直重试自旋消耗 CPU 资源3.只能操作单个变量CAS只能保证单个变量的原子性无法解决多个变量的原子操作 需用锁或AtomicInteger 封装对象2.自旋锁和自适应自旋锁2.1 自旋锁基于CAS实现的一种非阻塞锁,核心思想是线程获取锁失败时不直接阻塞而是再循环中不断重试自旋直到成功获取锁。而自适应自旋锁是自旋锁的优化版本会根据“过往经验”动态调整自旋次数是JVM中 Synchronized 锁升级的重要环节。2.1.1 为什么需要自旋锁传统悲观锁如 synchronized 早期实现获取锁失败时线程会被挂起从运行态到阻塞态这涉及操作系统的上下文切换开销很大。但实际场景中很多锁的持有时间极短比如几纳秒线程挂起再唤醒的时间可能比锁占用的时间还长。此时自旋重试比阻塞更高效——相当于“在门口等几秒而不是直接回家阻塞”2.1.2 自旋锁核心原理1.基于CAS原子操作实现线程自旋时不断用 CAS 检查锁是否被释放。2.自旋过程中线程处于运行态不是阻塞态,只是空耗CPU直到获取锁或自旋结束。2.1.3 JAVA 手动实现自旋锁import java.util.concurrent.atomic.AtomicBoolean; // 自旋锁核心CAS 循环重试 public class SpinLock { // 用 AtomicBoolean 标记锁状态false未锁定true已锁定 private AtomicBoolean locked new AtomicBoolean(false); // 获取锁自旋直到 CAS 成功 public void lock() { // CAS 尝试将 locked 从 false 改为 true while (!locked.compareAndSet(false, true)) { // 自旋空循环直到成功 // 注意实际开发中可加 Thread.yield() 让出CPU减少空耗 } } // 释放锁直接置为 false public void unlock() { locked.set(false); } // 测试 public static void main(String[] args) { SpinLock spinLock new SpinLock(); // 线程1获取锁 new Thread(() - { spinLock.lock(); try { System.out.println(线程1获取锁执行任务); Thread.sleep(100); // 模拟短时间持有锁 } catch (InterruptedException e) { e.printStackTrace(); } finally { spinLock.unlock(); System.out.println(线程1释放锁); } }).start(); // 线程2自旋等待锁 new Thread(() - { spinLock.lock(); try { System.out.println(线程2获取锁执行任务); } finally { spinLock.unlock(); System.out.println(线程2释放锁); } }).start(); } }执行结果线程1获取锁执行任务 线程1释放锁 线程2获取锁执行任务 线程2释放锁线程 2 在获取锁失败时会在while循环中自旋直到线程 1 释放锁后 CAS 成功。2.1.4 自旋锁的优缺点优点缺点无上下文切换开销短持有时间锁性能极高自旋空耗 CPU高冲突时导致 CPU 使用率飙升非阻塞线程不会被挂起自旋次数固定无法适配不同场景比如锁持有时间长时自旋纯浪费实现简单基于 CAS 即可可能导致 活锁多个线程同时自旋重试互相抢不到锁2.2 自适应自旋锁自适应自旋锁是 JDK 1.6 为synchronized引入的优化解决了普通自旋锁 自旋次数固定 的问题。2.2.1 核心原理自旋次数不固定而是根据「上一次获取该锁的自旋情况」动态调整如果上一次自旋成功获取了锁说明该锁的持有时间短本次自旋次数会增加比如从 10 次→20 次认为这次也大概率能快速拿到锁。如果上一次自旋失败了说明该锁的持有时间长本次自旋次数会减少甚至直接不自旋直接进入阻塞避免浪费 CPU。如果自旋次数超过阈值自动切换为阻塞传统悲观锁方式。2.2.2 自适应自旋锁的优势智能适配场景不用手动设置自旋次数JVM 自动根据历史经验调整。平衡性能与资源短锁自旋省开销长锁不自旋省 CPU。是 synchronized 锁升级的关键synchronized的锁升级流程无锁 → 偏向锁 → 轻量级锁自适应自旋 → 重量级锁。2.3 自旋锁 VS 自适应自旋锁 对比特性普通自旋锁自适应自旋锁自旋次数固定比如 10 次 / 20 次动态调整基于历史经验灵活性低高CPU 利用率高冲突时易空耗更合理减少无效自旋适用场景锁持有时间固定的简单场景复杂并发场景如 JVM 内部典型应用手动实现的简单自旋锁JDK 1.6 的 synchronized2.4 实战注意事项自旋锁适合短锁只有锁持有时间极短微秒 / 纳秒级时自旋才有意义如果锁持有时间长自旋会浪费大量 CPU。避免自旋次数过多手动实现自旋锁时可设置最大自旋次数比如 1000 次超过则放弃自旋转为阻塞。JVM 对自旋的控制可通过 JVM 参数调整自旋行为-XX:PreBlockSpin设置普通自旋锁的最大自旋次数JDK 1.6 后该参数失效自适应自旋接管。-XX:-UseSpinning关闭自旋锁所有失败直接阻塞。3.无锁、偏向锁、轻量级锁、重量级锁这些锁状态是 Java 为了优化synchronized关键字性能而设计的锁升级机制核心思想是在不同并发程度下使用成本最低的锁策略从无锁到重量级锁是一个单向升级的过程不会降级。3.1 无锁定义没有任何线程竞争资源所有线程都可以自由访问共享资源。本质不是真正的“锁”而是通过 CAS 乐观锁机制保证操作原子性避免阻塞。适合场景几乎无并发竞争的场景单线程操作。import java.util.concurrent.atomic.AtomicInteger; public class NoLockDemo { // 原子类底层通过 CAS 实现无锁操作 private static AtomicInteger count new AtomicInteger(0); public static void main(String[] args) { // 多线程自增但底层用 CAS 无锁实现 for (int i 0; i 5; i) { new Thread(() - { count.incrementAndGet(); // CAS 自增无锁竞争 System.out.println(Thread.currentThread().getName() : count.get()); }).start(); } } }3.2 偏向锁定义当只有一个线程反复获取同一把锁时JVM 会让该线程“偏向”这把锁——锁对象会记录当前线程的ID后续该线程获取锁时无需任何竞争操作直接返回。核心优化消除无竞争场景下的锁获取/释放开销比轻量级锁更高效。适用场景单一线程重复获取锁的场景单线程循环加锁。触发升级当有第二个线程尝试获取锁时偏向锁会升级为轻量级锁。关键特点默认开启JDK 1.6,可通过 -XX-UseBiasedLocking 关闭。偏向锁的撤销有一定延迟约4秒避免频繁撤销影响性能。3.3 轻量级锁定义当多个线程交替获取同一把锁无激烈竞争时JVM会使用轻量级锁——线程通过CAS操作尝试获取锁失败时不会立即阻塞而是自旋循环重试。核心优化避免线程阻塞/唤醒的内核态切换开销 自旋是用户态操作。适用场景多线程交替竞争锁短时间、低冲突。触发升级当自旋次数达到阈值默认 10 次或自旋线程数超过 CPU 核心数的一半时轻量级锁升级为重量级锁。3.4 重量级锁定义依赖操作系统的互斥量Mutex实现线程获取锁失败时会被挂起进入阻塞状态直到锁释放后被唤醒。核心特点开销大涉及用户态—— 内核态切换线程阻塞/唤醒成本高。适用场景高并发、长持有锁的场景自旋已无意义。synchronized 触发重量级锁public class HeavyLockDemo { private static final Object lock new Object(); public static void main(String[] args) { // 两个线程同时竞争锁最终触发重量级锁 new Thread(() - { synchronized (lock) { try { Thread.sleep(1000); // 长时间持有锁触发锁升级 System.out.println(线程1持有锁); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); new Thread(() - { synchronized (lock) { System.out.println(线程2获取锁); } }).start(); } }锁状态升级流程单向3.5 总结无锁基于 CAS 实现无竞争时最优无锁开销偏向锁单线程专属消除无竞争下的锁操作开销有新线程竞争时升级轻量级锁多线程交替竞争自旋 CAS 获取锁自旋失败则升级为重量级锁重量级锁依赖操作系统互斥量线程阻塞 / 唤醒开销大适用于高并发长持有场景。核心逻辑JVM 从 “乐观” 到 “悲观” 逐步调整锁策略尽可能降低锁的使用成本。

相关文章:

JAVA进阶-锁

1.悲观锁和乐观锁悲观锁:在修改数据时,一定有别的线程来使用,一定会发生并发冲突,所以在获取数据的时候会加锁。JAVA中的synchronized和lock都是悲观锁。乐观锁:在修改数据时,一定没有别的线程来使用&#…...

Cesium快速入门到精通系列教程二十三:综合

一、viewer.cesiumWidget.container.appendChild() 把你自定义的 HTML 元素(弹窗、按钮、图标等)添加到 Cesium 画布的容器里,让它显示在 3D 地球场景上。 // 1. 创建一个自定义弹窗 div const infoDiv = document.createElement(div); infoDiv.style.position = absolute…...

JAVA数据结构 DAY8-堆

本系列可作为JAVA学习系列的笔记,文中提到的一些练习的代码,小编会将代码复制下来,大家复制下来就可以练习了,方便大家学习。 点赞关注不迷路!您的点赞、关注和收藏是对小编最大的支持和鼓励! 系列文章目录…...

2026-03-17 每日作战任务:RAG 语料高效切分(Text Chunking)与处理

2026-03-17 每日作战任务:RAG 语料高效切分(Text Chunking)与处理每日学习代码关联仓库地址:https://gitee.com/lqx_learn/java-ai.git一、 业务场景 昨天我们运用 JDK 17 的 FileChannel 与 MappedByteBuffer,实现了大…...

Android Studio 安装教程(Windows 超详细图文版)

本教程将从 准备工作→ 下载 → Android Studio安装 → SDK配置 → 创建第一个项目 全流程讲解,适合 AndroidAndroid开发零基础入门。 一、Android Studio简介 Android Studio 是 Google 官方推出的 Android应用开发IDE,用于开发 Android APP。它基于 I…...

SPI子系统源码剖析--(2)Spi_Master驱动框架

1. spi_masterspi_master对应spi控制器,是对引脚的管理,同时可以通过cs引脚选择从设备发送消息2. SPI传输概述1.1 数据组织方式使用SPI传输时,最小的传输单位是"spi_transfer",对于一个设备,可以发起多个spi…...

速看!!安全员ABC证靠谱的查询方式有哪几种?分别是怎么查询呢?

很多人报考安全员都会有疑虑,担心自己考的安全员不是正规的,考出来没有用,不能在正规网站查询到,今天星禾智慧老师告诉您安全员ABC靠谱的查询方式,保证你拿到的证书不再有假🍎🧤一、湖北安全员A…...

软件综合项目-mqtt

依赖的第三方库https:CURL库SQLite:SQLite库MQTT库:Paho库MQTT属于应用层协议,支持其实现的传输协议为TCPHTTPS适用于传输的数据量比较大情况,传输方式为字符单向传输MQTT传输数量比较小,二进制传输&#x…...

2026人事系统排行榜:一体化+AI,11家企业谁是TOP选手?

2026年一体化AI人事系统TOP11深度评测:谁领跑AI原生时代?2026年,HR SaaS行业已全面迈入AI原生架构全链路一体化的竞争新阶段。企业对人系统的核心诉求,从“功能叠加AI”进化为“从底层架构融入AI”,要求AI能贯穿招聘、…...

ssm+java2026年毕设社区疫情管理系统【源码+论文】

本系统(程序源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容一、选题背景关于社区公共卫生应急管理问题的研究,现有研究主要以宏观层面的城市公共卫生体系构建、重大疫情应急响应机制为主&…...

【亲测好用】数据权限管理能力演示

导言: 作为一名企业管理者或业务人员,您是否曾遇到过这样的烦恼:(1)销售人员看到了不该看的财务数据?(2)合作伙伴访问了超出约定范围的信息?(3)不…...

Paperzz AI 毕业论文写作:从选题到成文,本科论文高效交付的智能解决方案

Paperzz-AI官网免费论文查重复率AIGC检测/开题报告/文献综述/论文初稿paperzz - 毕业论文-AIGC论文检测-AI智能降重-ai智能写作https://www.paperzz.cc/dissertation 在本科毕业论文的创作路上,从确定选题到完成初稿,从文献梳理到格式规范,每…...

Paperzz AI 初稿引擎:重构本科毕业论文写作,从选题到终稿一站式高效通关

Paperzz-AI官网免费论文查重复率AIGC检测/开题报告/文献综述/论文初稿paperzz - 毕业论文-AIGC论文检测-AI智能降重-ai智能写作https://www.paperzz.cc/dissertation 引言 本科毕业论文的创作,是大学生学业生涯的收官之战,也是对专业知识与学术能力的综…...

泰思特电子分享_EMC测试电流探头选型差异性及影响因素探讨

本文主要进行EMC测试电流探头选型差异性及影响因素探讨,围绕电流探头核心技术指标进行介绍,根据EMC测试不同标准、不同测试项目对电流探头的需求差异,分析了电流探头选型的关键影响因素以及国内外主流厂家不同型号产品的对比,为EM…...

基于能量分配的光伏混合储能系统仿真模型 ①光伏:采用mppt控制实现最大功率跟踪 ②蓄电池与超...

基于能量分配的光伏混合储能系统仿真模型 ①光伏:采用mppt控制实现最大功率跟踪 ②蓄电池与超级电容:构成混合储能系统,电池实现连续功率供应,超级电容提供瞬态功率供应 ③拓扑:光伏DC/DC采用boost变换器,混…...

APM使用LUA脚本发送实现遥控器PWM信号输出CAN协议信号

需求:由于舵机是CAN总线舵机,需实现APM开源飞控遥控器输入PWM通道到CAN的发送。 方法1:修改APM固件源码,编译,运行,测试。实现复杂。 方法2:使用lua脚本。实现简单 目前采用方法2,使…...

LangGraph 核心概念

LangGraph是LangChain 生态的 “进阶编排框架”,是 AgentExecutor升级版,基于图结构解决复杂工作流 / 多智能体问题,兼容 LangChain 所有组件。AgentExecutor 是「单智能体固定循环执行器」,适合简单线性任务;LangGrap…...

零基础搭建免费IP代理池:从原理到实战的保姆级指南

在数据驱动型业务中,很多企业都会接触到“IP代理池”这一概念。尤其是在进行公开数据整合、市场信息监测等场景时,单一IP往往难以支撑持续稳定的请求需求,这时代理池就成为重要基础设施。但对于初学者来说,“搭建代理池”听起来复…...

努力学习了一辈子,突然发现学习没什么用了

从小,我是众人眼中的 “学习标兵”。到现在,每天一节法语,一篇英语阅读,依然雷打不动:但最近几个月,随着老杨的“眨眼猫会务智能体”中对报名、签到、查座、AI会务助理的全面 “AI化改造”,老杨…...

大模型的那点事儿

大模型参数调优完全指南:从模型选择到参数配置 作者:虾兵一号 发布时间:2026-03-17 关键词:大模型参数、模型选择、Temperature、Top P、推理参数、LLM调优 一、前言 在使用大模型 API 时,两个问题最让人头疼&#xf…...

python-web自动化-selenium(1)

目录 资源 驱动器下载流程 设置、创建启动浏览器 设置浏览器Options() 创建启动浏览器webdriver.Chrome() 完整代码 打开网页,关闭标签页,关闭浏览器 打开网址get() 关闭当前标签页close() 完整代码 最大化最小化 最大化maximize_window() 最…...

AI智能水库图像识别数据集 水面漂浮物识别 水面分割识别 河道护栏分割数据集 YOLO格式数据集第10573期

数据集文档数据集概览 本数据集为实例分割场景专用数据集,聚焦于水处理场景下的关键目标识别与分割任务,为工业视觉算法提供高质量标注数据支撑。项目内容类别数量及中文名称4类:水面、粗格栅1、粗格栅2、悬浮物数据总量100张数据集格式YOLO核…...

关于密码破解的方式

当重启虚拟机或者开启虚拟机时,当界面跳出时,快速将鼠标点进虚拟机中,按向下或者向上箭头防止界面跳转,并按如下步骤进行:1 在界面中选择第二个选项2 按e键进入如下界面,按向下向上键将光标移动到quiet单词后面&#x…...

SAP 系统配置、落地即用的《SAP 成本分摊循环配置清单》,包含事务码、主数据、循环结构、分配 / 分摊规则、计算公式、案例数据

SAP 系统配置、落地即用的《SAP 成本分摊循环配置清单》,包含事务码、主数据、循环结构、分配 / 分摊规则、计算公式、案例数据一、通用主数据(所有案例共用,先建好)1. 成本中心(标准示例)成本中心名称类型…...

基于MATLAB_SIMULINK_SIMSCAPE建模的用于组件尺寸的电动和混合动力飞机模型

基于MATLAB/SIMULINK/SIMSCAPE建模的用于组件尺寸的电动和混合动力飞机模型第一步:主脚本 (AircraftSizingMain.m) 在 MATLAB 中运行此脚本,它将定义参数并启动仿真。 matlab 编辑 1%% Aircraft Component Sizing Simulation Script 2% 适用于电动 (AE) …...

C 语言03:结构体——自定义数据类型的万能基石

结构体(struct)是 C 语言的核心自定义数据类型,用于将不同类型的数据(如姓名、年龄、日期)打包成一个整体,极大简化了复杂数据的管理。本文从定义到使用,极简解析结构体的核心用法。一、结构体类…...

SAP 成本分摊逻辑与案例(含具体数据)

SAP 成本分摊核心是通过 ** 分配(Allocation)与分摊(Assessment)** 两种循环,将间接成本中心归集的费用,按预设规则(统计指标、比例、作业量等)结转至直接成本中心、生产订单、内部订…...

C语言当中的字符函数

字符分类函数可以很好的帮助我们进行字符的分类其中头文件为<ctype.h>现在举个列子&#xff0c;进行大小写转换islower运用函数的代码int i0&#xff1b;char str【】“CBASJDHsfjaf”&#xff1b;char c;while(str[i]){cstr[i];if(islower(c))c-32;putchar(c)i;}远高于平…...

思特威SC1220IOT——为AI眼镜量身打造的超低功耗影像之心

导读: 随着AI大模型向端侧迁移,AI智能眼镜被视为继智能手机之后最具潜力的下一代个人计算平台。然而,要在极其有限的轻量化镜架中塞进高性能的“眼睛”,同时保证全天候续航与即时响应,对核心的CMOS图像传感器提出了严苛挑战。近日,国内技术先进的CMOS图像传感器供应商思特…...

算法设计与分析-习题8.3

目录 1.完成本节构造最优二叉查找树的例题中余下的计算。 2. a.算法OptimalBST的时间效率为什么是立方级的? b.算法 OptimalBST 的空间效率为什么是平方级的? 3.写一个线性时间算法的伪代码&#xff0c;来从根表中生成最优二叉查找树。 4.请设计一种在常量时间(每个求和…...