【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 + 自旋尝试获取锁,不阻塞。 场景:线程交替访问,锁执行时间短。

重量级锁

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

相关推荐
三品吉他手会点灯18 小时前
C语言学习笔记 - 50.流程控制4 - 流程控制为什么非常非常重要
c语言·开发语言·笔记·学习
在放️21 小时前
Python 爬虫 · 第三方代理接入与合规使用
开发语言·爬虫·python
KANGBboy21 小时前
java知识五(继承)
java·开发语言
c++之路21 小时前
Bazel C++ 构建系列文档(三):构建第一个 C++ 项目
开发语言·c++
AI人工智能+电脑小能手21 小时前
【大白话说Java面试题 第117题】【并发篇】第17题:线程有几种状态,之间如何转换?
java·开发语言·面试
聚名网1 天前
域名net,com,cn有区别吗?有哪些不同呢?
服务器·开发语言·php
牛油果子哥q1 天前
STL set与map底层精讲,红黑树适配原理、有序去重特性、迭代器遍历、API实战与面试核心考点全解
开发语言·数据结构·c++·面试
foundbug9991 天前
直流电机 PID 速度控制 MATLAB 仿真程序
开发语言·matlab
Tian_Hang1 天前
C++原型模式(Protype)
开发语言·c++·算法
天天讯通1 天前
OKCC 呼叫中心安全性能全解析:技术防护与管理措施指南
大数据·开发语言·网络·人工智能·安全·语音识别