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

关于使用锁的沉淀信息量

1.java中提供了哪些锁
2.syn的实现机制是什么
3,在代码中如何使用
4.在使用中的实际机制是什么
5.在项目中,用的话坑是什么

Java中的锁体系与synchronized深度解析

一、Java中提供了哪些锁

Java中的锁可以从多个维度进行分类:

按实现方式分类:

  • 内置锁(synchronized):由JVM层面实现,加锁/释放锁自动完成,无需开发者干预
  • 显式锁(Lock接口):如ReentrantLock、ReentrantReadWriteLock等,需手动加锁和释放锁,提供更灵活的锁控制

按锁的特性分类:

分类维度锁类型说明代表实现
锁持有方式独占锁同一时刻只能一个线程持有synchronized、ReentrantLock
共享锁多个线程可同时持有ReentrantReadWriteLock的读锁、Semaphore
竞争机制公平锁线程按申请顺序获取锁ReentrantLock(true)
非公平锁允许插队,吞吐量更高synchronized、ReentrantLock(false)
重入性可重入锁同一线程可多次获取同一锁synchronized、ReentrantLock
不可重入锁同一线程重复获取会死锁需自定义实现
实现机制乐观锁更新时检查版本,适用于读多写少AtomicInteger(CAS实现)
悲观锁操作前先加锁,适用于写多读少synchronized、ReentrantLock

并发工具包中的锁:

  • Atomic原子类:基于CAS实现的乐观锁,包括AtomicInteger、AtomicLong、AtomicReference等
  • 读写锁:ReentrantReadWriteLock,读读共享、读写互斥
  • StampedLock:Java 8引入,支持乐观读
  • Semaphore:信号量,控制同时访问的线程数

二、synchronized的实现机制

2.1 底层实现原理

synchronized的锁信息存储在**Java对象的对象头(Mark Word)**中。HotSpot虚拟机中,对象头Mark Word(64位)根据锁状态动态存储不同内容:

锁状态锁标志位存储内容
无锁01哈希码、分代年龄
偏向锁01线程ID、偏向时间戳
轻量级锁00指向线程栈中Lock Record的指针
重量级锁10指向ObjectMonitor的指针
2.2 锁升级机制(JDK 1.6+)

JVM引入了锁升级机制来优化性能,路径为:无锁 → 偏向锁 → 轻量级锁 → 重量级锁,升级是单向不可逆的:

① 偏向锁

  • 核心思想:锁会偏向于第一个获得它的线程,消除无竞争下的同步开销
  • 加锁:通过CAS将线程ID记录到Mark Word中
  • 撤销:当其他线程竞争时,在全局安全点撤销偏向锁
  • 注意:JDK 15+默认禁用偏向锁,需通过-XX:+UseBiasedLocking开启

② 轻量级锁

  • 核心思想:多线程交替执行时,通过CAS避免内核态切换
  • 加锁:JVM在当前线程栈帧中创建Lock Record,CAS将Mark Word替换为指向Lock Record的指针
  • 自旋:CAS失败时,通过自适应自旋尝试获取锁,自旋达到阈值后升级为重量级锁

③ 重量级锁

  • 底层基于操作系统的互斥量(mutex)实现,涉及用户态与内核态切换
  • 核心载体:C++实现的ObjectMonitor对象,包含_owner(持有锁线程)、_entryList(阻塞队列)、_waitSet(等待队列)等结构
2.3 synchronized的三大作用
  • 原子性:确保同一时刻只有一个线程执行同步代码
  • 可见性:锁释放前会将修改同步回主内存,锁获取时会清空工作内存重新读取
  • 有序性:解决重排序问题

三、代码中的使用方式

3.1 三种基本使用方式
// 1. 修饰实例方法——锁当前实例对象publicsynchronizedvoidmethodA(){// 同步代码}// 2. 修饰静态方法——锁当前类的Class对象publicstaticsynchronizedvoidmethodB(){// 同步代码}// 3. 修饰代码块——锁指定对象publicvoidmethodC(){synchronized(this){// 锁当前实例// 同步代码}privatefinalObjectlock=newObject();synchronized(lock){// 锁自定义对象// 同步代码}}
3.2 八种常见使用场景示例
publicclassSynchronizedDemo{privatestaticSynchronizedDemoinstance=newSynchronizedDemo();// 场景1:同一对象,两个线程访问同一同步方法 → 线程安全(串行执行)publicsynchronizedvoidmethod1(){...}// 场景2:两个不同对象,访问同步方法 → 线程不安全(并行执行)// 场景3:普通方法 VS 同步方法 → 普通方法不受影响,可并行publicvoidnormalMethod(){...}publicsynchronizedvoidsyncMethod(){...}// 场景4:静态同步方法 VS 非静态同步方法 → 锁对象不同,可并行publicstaticsynchronizedvoidstaticMethod(){...}// 类锁publicsynchronizedvoidinstanceMethod(){...}// 对象锁// 场景5:同一个对象的不同同步方法 → 线程安全(同一把锁)publicsynchronizedvoidmethodA(){...}publicsynchronizedvoidmethodB(){...}}
3.3 锁对象的选择原则
  • 锁this/实例对象:控制同一实例的多个同步方法互斥
  • 锁Class对象:控制类的所有实例的静态同步方法互斥
  • 锁私有Object对象:精细控制锁粒度,避免对外暴露锁对象

四、使用中的实际执行机制

4.1 锁的获取与释放机制
  • 可重入性:同一线程可多次获取同一把锁,重入次数会记录,释放时需释放相同次数
  • 自动释放:同步方法/代码块执行完毕或抛出异常时,JVM自动释放锁
  • 阻塞与唤醒:竞争失败的线程进入阻塞状态,由JVM负责调度唤醒
4.2 锁竞争的实际流程
// 模拟锁升级过程privatestaticfinalObjectLOCK=newObject();publicvoiddemo(){synchronized(LOCK){// 第一次获取:偏向锁// 第二次同一线程获取:重入(仍为偏向锁)// 其他线程竞争:升级为轻量级锁(自旋等待)// 竞争激烈(自旋超时):升级为重量级锁}}
4.3 执行时的性能特点
  • 无竞争:偏向锁开销极小,几乎无性能损失
  • 轻度竞争:轻量级锁+自旋,避免内核态切换,性能较好
  • 重度竞争:重量级锁,线程阻塞涉及内核态切换,性能较差

五、项目中使用synchronized的坑与避坑指南

坑1:锁对象使用不当
// ❌ 错误:使用包装类或字符串作为锁对象privatefinalIntegerlock=0;// Integer是不可变对象,值变化时锁对象改变privatefinalStringlock="lock";// 字符串常量池导致意外共享// ✅ 正确:使用专用的final对象privatefinalObjectlock=newObject();
坑2:锁范围过大导致性能问题
// ❌ 错误:在锁内执行耗时操作publicsynchronizedvoidbadMethod(){// 数据库查询、网络调用等耗时操作// 导致锁持有时间过长,其他线程长时间等待}// ✅ 正确:缩小锁范围publicvoidgoodMethod(){// 非耗时操作在锁外执行Datadata=prepareData();synchronized(lock){// 仅同步必要的共享变量操作updateSharedData(data);}}
坑3:同步方法中调用非同步方法
// ❌ 危险:同步方法中调用非同步方法publicsynchronizedvoidsyncMethod(){unsafeMethod();// 若其他线程直接调用unsafeMethod,会破坏线程安全}publicvoidunsafeMethod(){// 修改共享变量,不是线程安全的}// ✅ 方案:保持一致性,所有涉及共享变量的方法都加锁publicsynchronizedvoidsyncMethod(){safeMethod();}publicsynchronizedvoidsafeMethod(){...}
坑4:死锁问题
// ❌ 错误:嵌套锁导致死锁classDeadlockRisk{privatefinalObjectlockA=newObject();privatefinalObjectlockB=newObject();publicvoidmethod1(){synchronized(lockA){synchronized(lockB){// 线程1持有lockA等待lockB// ...}}}publicvoidmethod2(){synchronized(lockB){synchronized(lockA){// 线程2持有lockB等待lockA → 死锁// ...}}}}// ✅ 正确:保证所有线程以相同的顺序获取锁publicvoidmethod1(){synchronized(lockA){synchronized(lockB){...}}}publicvoidmethod2(){synchronized(lockA){// 相同顺序synchronized(lockB){...}}}
坑5:忘记锁的是对象还是引用
// ❌ 错误:锁对象引用被改变privateObjectlock=newObject();publicvoidbadMethod(){synchronized(lock){lock=newObject();// 锁对象改变,其他线程可能进入}}// ✅ 正确:使用final修饰锁对象privatefinalObjectlock=newObject();
坑6:认为volatile能替代synchronized
// ❌ 错误:volatile不保证复合操作的原子性privatevolatileintcount=0;publicvoidincrement(){count++;// 非原子操作,线程不安全!}// ✅ 正确:使用synchronized保证原子性privateintcount=0;publicsynchronizedvoidincrement(){count++;}
坑7:JDK版本差异导致的锁行为变化
  • JDK 1.6前:synchronized一直是重量级锁,性能较差
  • JDK 1.6-14:默认启用偏向锁,有延迟(启动后4-5秒生效)
  • JDK 15+:默认禁用偏向锁,需要手动开启-XX:+UseBiasedLocking

最佳实践建议

  1. 优先使用synchronized,只有需要更高级功能(如可中断、超时、公平锁)时才用Lock
  2. 尽量缩小同步代码块的范围,减少锁持有时间
  3. 避免在锁内调用外部方法(可能持锁时间长或导致死锁)
  4. 使用专用private final对象作为锁,避免锁暴露
  5. 通过JOL工具观察对象头,验证锁状态
http://www.cnnetsun.cn/news/2162142.html

相关文章:

  • AI 时代下 BI 工具的进化:FineBI 对话式 BI 如何让数据分析人人可用?
  • 抖音无水印下载器:从零到精通的完整指南
  • 手机号逆向查询QQ号:3分钟快速找回遗忘账号的完整方案
  • 手把手教你复现GitLab CVE-2023-7028漏洞(附Burp Suite抓包实战截图)
  • Kubernetes智能运维新范式:kube-copilot如何用AI大语言模型革新kubectl体验
  • Verification安全验证指南:论文AIGC检测高效过关方案
  • Cesium-Wind终极指南:3步快速创建动态3D风场可视化
  • IntelliJ IDEA HTTP Client隐藏技巧:用脚本和动态变量让你的接口测试自动化起来
  • 通过 curl 命令快速测试 Taotoken 的 OpenAI 兼容接口是否通畅
  • 企业如何利用多模型聚合平台优化 AI 应用开发成本与效率
  • 一篇讲透:如何用碳浆+单层FSS,把雷达反射降低28dB?
  • FPGA高速接口调试笔记:用Bitslice原语抓取DDR数据,我踩过的那些坑
  • Intel Mac降级Big Sur前必看:用时间机器完整备份与恢复的实战教程
  • FF14动画跳过插件:告别副本等待的终极解决方案
  • 微信单向好友终极检测指南:快速发现谁已删除或拉黑你
  • BilldDesk终极指南:为什么这款免费远程桌面软件正在改变游戏规则?
  • 从Kali到实战:手把手教你用CobaltStrike 4.0搭建渗透测试环境(附中文汉化教程)
  • SkeyeVSS开发常见问题FAQ: 录像计划与定时任务不生效
  • 别再手动切模型了!用HuggingGPT(JARVIS)一键调用HuggingFace全栈AI模型
  • 零基础复现Claude Code(八):反思与展望——我们得到了什么,还缺什么?
  • 别再问PhotoPrism怎么多用户了!用Docker Compose一键部署全家桶(保姆级教程)
  • 解放C盘空间:FreeMove如何让你轻松迁移大文件而不破坏程序功能?
  • 从发现到交付,安全验证的活能不能让AI干?我拆解了这两款刚开源的AI安全工具,发现有点东西
  • 第十九天 | 1047. 删除字符串中的所有相邻重复项
  • 告别歌词获取难题:高效智能的163MusicLyrics歌词下载工具
  • 摩尔线程首份财报:营收高增但盈利待考,破局需拓展商业客群
  • Windows DLL注入新选择:Xenos如何让复杂操作变得简单
  • STM32H723ZGT6双CAN(FDCAN1/FDCAN2)独立收发实战:CubeMX配置与中断处理详解
  • AutoDock Vina终极指南:如何轻松处理含硼药物分子的精准对接
  • 2026 跨境独立站实战:Taoify 从建站到出单全流程解析摘要