【JUC第二章上】:锁机制&关键字

🔥你好我是fengxin_rou这是我的个人主页 fengxin_rou的主页

❄️欢迎查看我的专栏我的专栏

《Java后端学习》《JAVASE基础》《JUC并发》《redis》《JVM虚拟机》《MYSQL》《黑马点评》《rabbitmq》《JavaWeb+AI的talis学习系统》《苍穹外卖》

目录

[synchronized 底层原理?](#synchronized 底层原理?)

[synchronized 锁升级流程:](#synchronized 锁升级流程:)

无锁:

偏向锁:

[2. 偏向锁(单线程无竞争)](#2. 偏向锁(单线程无竞争))

偏向锁撤销

[3. 轻量级锁(自旋锁,短时间、轻度竞争)](#3. 轻量级锁(自旋锁,短时间、轻度竞争))

轻量级锁竞争

[自适应自旋(JDK 1.6+)](#自适应自旋(JDK 1.6+))

[4. 重量级锁(高竞争、长持有)](#4. 重量级锁(高竞争、长持有))

最终锁升级路径(标准总结)

[JDK 15 以前(经典路径)](#JDK 15 以前(经典路径))

[JDK 15+(现代 JVM,已废弃偏向锁)](#JDK 15+(现代 JVM,已废弃偏向锁))

锁升级核心思想

偏向锁、轻量级锁、重量级锁各自原理和适用场景?

[1. 偏向锁(Biased Lock)](#1. 偏向锁(Biased Lock))

原理

特点

适用场景

[2. 轻量级锁(Lightweight Lock)](#2. 轻量级锁(Lightweight Lock))

原理

特点

适用场景

[3. 重量级锁(Heavyweight Lock)](#3. 重量级锁(Heavyweight Lock))

原理

特点

适用场景

总结

偏向锁

轻量级锁

重量级锁


synchronized 底层原理?

synchronized是Java提供的原子性内置锁,这种内置的并且使用者看不到的锁也被称为监视器锁

一个同步块里只有一个锁对象,然后里面的线程都想要使用这个对象,想要使用的都执行monitorenter命令都在enterList里面争抢锁 ,成功的就计数器加1,失败的就继续在enterList 里面等待,等锁释放了就monitorexist计数器-1,当线程执行wait方法释放锁后会进入waitList队列

synchronized 锁升级流程:

无锁→偏向锁→轻量级锁→重量级锁

这个机制的核心在于对象头中的Mark Word,它会根据锁状态存储不同的信息,通过其中的锁标志位来标识当前锁处于什么状态。

无锁:

当一个对象刚创建出来的时候,没有线程访问他 ,并且mark word里面存储的是他的hashcode、分代年龄等信息,锁标志位是0、1,偏向锁位是0,如果使用了hashcode方法,就不能升级到偏向锁,因为偏向锁需要用Mark word的空间来存储当前线程ID,hashcode也要占用这一部分,冲突了

偏向锁:

2. 偏向锁(单线程无竞争)

  • 第一个线程 进入同步块时,锁升级为偏向锁
  • 通过 CAS 操作 将线程 ID 记录到对象头 Mark Word 中。
  • 锁标志位保持 01 ,偏向标志位改为 1
  • 该线程再次进入 同步块时,只需判断 Mark Word 中的线程 ID 是否是自己,无需加锁 / 解锁,效率极高。

偏向锁撤销

  • 第二个线程 尝试竞争锁时,偏向锁立即撤销
  • 撤销需要到达安全点,暂停原线程,判断是否仍在同步块中,然后清除偏向标记。
  • 偏向锁撤销开销较大,竞争一旦出现,就会升级到轻量级锁。

JDK 15+ 默认禁用偏向锁,JDK 18+ 彻底废弃,现代 JVM 锁升级路径: 无锁 → 轻量级锁 → 重量级锁


3. 轻量级锁(自旋锁,短时间、轻度竞争)

偏向锁撤销后,进入轻量级锁阶段:

  1. 线程在自己栈帧 中创建锁记录(Lock Record)
  2. 将对象头的 Mark Word 复制到锁记录中。
  3. 使用 CAS 操作 尝试将对象头的 Mark Word 替换为指向锁记录的指针
  4. 如果 CAS 成功,当前线程获取轻量级锁 ,锁标志位变为 00

轻量级锁竞争

  • 如果 CAS 失败,说明有其他线程竞争。
  • 当前线程开始自旋,循环重试 CAS 尝试获取锁。
  • 自旋是用 CPU 时间换避免线程阻塞 的开销,适合锁执行时间很短的场景。

自适应自旋(JDK 1.6+)

  • JVM 会根据历史自旋成功率动态调整自旋次数
  • 上次成功 → 自旋更久;上次失败 → 快速放弃。

4. 重量级锁(高竞争、长持有)

当自旋达到阈值仍未获取锁,或出现多线程同时竞争 时: 轻量级锁膨胀为重量级锁

  • 锁标志位变为 10
  • Mark Word 指向 Monitor(监视器锁) 对象。
  • 未获取锁的线程进入 EntryList 阻塞排队。
  • 依赖操作系统 Mutex 互斥量 实现。
  • 线程阻塞 / 唤醒需要 用户态 ↔ 内核态切换,开销最大。

优点:竞争激烈、锁持有时间长时,比自旋更节省 CPU。


最终锁升级路径(标准总结)

JDK 15 以前(经典路径)

无锁 → 偏向锁 → 轻量级锁 → 重量级锁

JDK 15+(现代 JVM,已废弃偏向锁)

无锁 → 轻量级锁 → 重量级

锁升级核心思想

根据线程竞争程度,自动选择成本最低的锁机制: 无竞争用偏向锁,轻度竞争用轻量级锁,高竞争用重量级锁。 用复杂度换性能,让 synchronized 在各种场景都高效。

偏向锁、轻量级锁、重量级锁各自原理和适用场景?

1. 偏向锁(Biased Lock)

原理

  • 锁一开始偏向第一个获取它的线程
  • 在对象头 Mark Word记录线程 ID
  • 下次这个线程再进来,不需要 CAS、不需要抢锁,直接判断 ID 是不是自己,是就直接进同步块。
  • 锁标志位:01,偏向位 = 1
  • 一旦出现第二个线程竞争,偏向锁立刻撤销,升级为轻量级锁。

特点

  • 无锁开销、最快
  • 只服务一个线程
  • 撤销偏向锁的成本很高

适用场景

只有一个线程反复进入同步块,完全无竞争。


2. 轻量级锁(Lightweight Lock)

原理

  • 线程在自己栈帧 中创建锁记录(Lock Record)
  • CAS 尝试把对象头的 Mark Word 替换成指向锁记录的指针
  • CAS 成功 = 加锁成功
  • CAS 失败 = 线程开始自旋,循环重试
  • 锁标志位:00

特点

  • 不阻塞、不进入内核态
  • 自旋消耗 CPU,但避免线程切换开销
  • 竞争变激烈就膨胀为重量级锁

适用场景

多个线程交替访问同步块,轻度竞争,锁执行时间非常短。


3. 重量级锁(Heavyweight Lock)

原理

  • 依赖 操作系统 Mutex 互斥锁
  • 对象头 Mark Word 指向 Monitor
  • 抢不到锁的线程进入 EntryList 阻塞
  • 阻塞 / 唤醒需要 用户态 ↔ 内核态切换
  • 锁标志位:10

特点

  • 线程会阻塞,不消耗 CPU
  • 切换成本最高、最慢
  • 最稳定、最安全

适用场景

竞争激烈,锁执行时间长,多线程同时争抢。


总结

偏向锁

原理 :锁偏向第一个线程,记录线程 ID,无竞争无需加锁。 场景:单线程重复访问,无竞争。

轻量级锁

原理 :使用 CAS + 自旋尝试获取锁,不阻塞。 场景:线程交替访问,锁执行时间短。

重量级锁

原理 :依赖操作系统互斥量,线程阻塞排队。 场景:高竞争、锁执行时间长。

相关推荐
杰克尼2 分钟前
天机学堂复习总结(day03-day04)
java·开发语言·redis·elasticsearch·spring cloud
x***r15130 分钟前
jdk-11.0.16.1_windows使用步骤详解(附JDK 11环境变量配置与验证教程)
java·开发语言·windows
luck_bor1 小时前
File类&递归作业
java·开发语言
努力努力再努力wz5 小时前
【Qt入门系列】:按钮组件全解析:从 QAbstractButton 到快捷键事件、单选与复选机制
c语言·开发语言·数据结构·c++·git·qt·github
skywalk81635 小时前
言知(Yanzhi)系统提升建议报告和完工报告 by AutoCoder
开发语言·编程
yunn_6 小时前
单例模式两种实现方法
开发语言·c++·单例模式
我材不敲代码6 小时前
Python基础:列表详解、增删改查及常用高阶操作
开发语言·windows·python
AI玫瑰助手6 小时前
Python运算符:成员运算符(in/not in)的使用场景
开发语言·python·信息可视化
AI人工智能+电脑小能手6 小时前
【大白话说Java面试题 第77题】【Mysql篇】第7题:回表查询与全表扫描的区别?
java·开发语言·数据库·mysql·面试
水木流年追梦6 小时前
大模型入门-大模型分布式训练2
开发语言·分布式·python·算法·正则表达式·prompt