java synchronized 锁升级:从偏向锁到重量级锁的底层自适应优化

简介: `synchronized` 是Java核心同步机制,JDK 1.6起引入锁升级(无锁→偏向锁→轻量级锁→重量级锁),依托对象头Mark Word动态适配竞争强度,兼顾性能与稳定性,是并发编程必懂的底层逻辑。(239字)

synchronized 是Java原生最核心的同步原语,早期因“重量级锁”的高开销被诟病,JDK 1.6 引入的锁升级机制,让它能根据竞争场景自适应切换锁状态,性能实现质的飞跃,是并发编程必须吃透的底层逻辑。

一、锁的底层载体

synchronized 的底层依托于 Java对象头(Mark Word) 与管程(Monitor)实现。
Java对象的Mark Word会动态存储锁状态、持有线程ID、偏向时间戳、分代年龄等信息,锁升级的本质,就是Mark Word在不同竞争场景下的状态流转,全程仅支持升级、不支持降级(仅偏向锁可撤销)。

二、完整的锁升级链路

JVM会根据竞争激烈程度,逐级升级锁,全程无人工干预,适配绝大多数业务场景。

  1. 无锁状态
    对象刚创建、未被任何线程竞争时,Mark Word处于无锁状态,仅存储对象的哈希码、分代年龄等基础信息。

  2. 偏向锁(无竞争场景)
    这是JVM的极致优化:锁首次被单个线程访问时,会通过CAS将该线程ID写入Mark Word,标记为偏向锁。后续该线程进入同步块时,无需任何CAS加锁/解锁操作,几乎零开销
    它解决了现实中“90%的锁全程只有一个线程持有”的场景,彻底消除无竞争场景下的同步开销。

  3. 轻量级锁(轻度竞争场景)
    当出现第二个线程竞争锁时,偏向锁立即撤销,升级为轻量级锁。
    竞争线程会通过自适应CAS自旋尝试获取锁,全程在用户态执行,无内核态切换,不会阻塞线程。JVM会根据历史自旋成功率动态调整自旋次数,避免CPU空耗。

  4. 重量级锁(高强度竞争场景)
    当自旋多次失败、多线程同时竞争、锁持有时间过长时,轻量级锁会立即升级为重量级锁。
    此时锁会关联对象的Monitor管程,未抢到锁的线程会进入阻塞队列,发生用户态与内核态的切换,开销最高,但不会持续占用CPU,适合高竞争、长耗时的同步场景。

三、核心认知误区与最佳实践

  • 常见误区:synchronized 一上来就是重量级锁。事实上JDK 1.6+默认开启锁升级,会根据竞争程度自适应切换,绝大多数低竞争场景下开销极低。
  • 核心禁忌:同步块尽量精简,避免锁持有时间过长,导致锁快速升级到重量级锁;高并发场景需合理拆分锁粒度,降低竞争强度。

结语

synchronized 的锁升级机制,是JVM对现实并发场景的极致工程优化,兼顾了无竞争场景的低开销与高竞争场景的稳定性。理解它的底层逻辑,不仅能写出更高效的并发代码,更是排查并发死锁、性能瓶颈的核心前提。

相关文章
|
6月前
|
SQL 缓存 算法
Java 内存模型与 volatile:并发底层的轻量级同步核心
`volatile` 是JMM核心轻量级同步关键字,通过内存屏障禁用重排、借助MESI协议保障可见性,精准解决可见性与有序性(不保证原子性),是DCL单例、状态标志等场景的基石,堪称高效并发编程的“轻量级钥匙”。(239字)
385 7
|
5月前
|
存储 C语言
C语言深度解析:static 关键字的三大核心本质
`static`是C语言中兼具生命周期、作用域与链接属性控制的关键字:修饰局部变量使其驻留静态区、仅初始化一次;修饰全局变量或函数则限定为文件内私有,有效避免命名冲突、实现模块化封装与内存精准管理。(239字)
|
5月前
|
Java 调度 开发者
Java AQS:JUC 并发体系的底层同步框架基石
AQS(AbstractQueuedSynchronizer)是Java并发包(JUC)的底层核心,以volatile state + CLH双向队列统一实现同步控制。支持独占(如ReentrantLock)与共享(如Semaphore、CountDownLatch)两种模式,通过模板方法封装排队、阻塞/唤醒等通用逻辑,是理解与定制高性能同步组件的关键基石。(239字)
657 7
|
canal 缓存 NoSQL
【Redis系列笔记】双写一致性
本文讨论了缓存不一致问题及其后果,如价格显示错误和订单计算错误。问题主要源于并发和双写操作的异常。解决方案包括使用分布式锁(但可能导致性能下降和复杂性增加)、延迟双删策略(通过延迟删除缓存来等待数据同步)以及异步同步方法,如通过Canal和MQ实现数据的最终一致性。面试中,可以提及这些策略来确保数据库和缓存数据的一致性。
1966 1
【Redis系列笔记】双写一致性
|
5月前
|
缓存 前端开发 JavaScript
前端渲染性能的底层逻辑:跳出重排重绘的表层认知
本文揭示前端渲染优化的本质:性能瓶颈不在“重排重绘”本身,而在于浏览器渲染流水线(JS→样式→布局→绘制→合成)的**触发频次与全链路开销**。主流框架的优化逻辑——批量更新、精准更新、合成层隔离——正是围绕降低流水线调用成本展开。落地只需三招:收敛更新时机、善用编译期优化、慎用合成层。
|
5月前
|
存储 缓存 Java
Java 对象内存布局:从堆内存储到伪共享优化的底层真相
Java对象内存布局是JVM核心基础:含对象头(Mark Word+Klass指针)、实例数据(字段重排序优化)和对齐填充(8字节对齐)。它直接影响内存占用、GC效率、锁升级与伪共享性能。掌握此机制,是深入理解并发优化(如@Contended)、指针压缩及高性能编程的必经之路。(239字)
555 111
|
5月前
|
存储 C语言 内存技术
C语言深度解析:大小端字节序——多字节数据的底层存储规则
大小端指CPU对多字节数据在内存中的存放顺序:大端高字节存低地址,小端反之。x86/ARM默认小端,网络字节序统一为大端。跨平台、网络通信、二进制协议开发中必须显式处理字节序转换,否则数据解析必错。
1077 138
|
8月前
|
存储 缓存 监控
从GC日志小白到分析大神:GCEasy实战全攻略
GCEasy是Java GC日志分析利器,支持多种垃圾收集器,通过可视化报表与智能诊断,帮助开发者快速定位内存泄漏、GC频繁等问题。本文结合实战案例,详解其原理、使用方法及性能优化策略,提升系统稳定性与并发能力。
1178 1
|
5月前
|
存储 安全 编译器
C语言深度解析:变长数组(VLA)的底层逻辑与避坑指南
变长数组(VLA)是C99引入的栈上动态数组,长度运行时确定,访问快但无安全检查。易致栈溢出、野指针、跨平台兼容问题,仅适用于小尺寸、短生命周期场景,大数组务必用malloc。
611 38
|
12月前
|
缓存 Java Spring
Spring循环依赖:当两个Bean陷入鸡生蛋死循环时...
Spring中循环依赖问题常见于Bean相互依赖时,尤其在单例模式下。文章深入解析了循环依赖的成因及Spring的三级缓存解决方案,帮助理解Bean生命周期与依赖管理。

热门文章

最新文章