Java锁的升级流程详解:无锁、偏向锁、轻量级锁、重量级锁
在Java中,为了在多线程并发场景下既保证线程安全,又尽可能提高性能,JVM针对synchronized实现了锁的优化升级机制。
锁可以从无锁逐步升级到偏向锁、轻量级锁,最后是重量级锁。
话不多说,发车!
一、无锁(Unlocked)
无锁,顾名思义,表示对象处于未加锁状态。
特点:对象正常状态,没有线程竞争。
适用场景:对象没有被任何线程加锁的情况下,大家可以自由访问。
性能:最快,不需要任何同步开销。
在jdk1.6之后默认是开启的
二、偏向锁(Biased Lock)
偏向锁是JDK 1.6引入的一种锁优化手段。
它假设大部分情况下,锁都是由同一个线程持有的,所以不做真正的同步操作,只在对象头中记录线程ID。
加锁流程:
第一个线程访问时,JVM会偏向该线程,记录它的线程ID。
后续该线程进入同步块时,只需快速判断对象头是否偏向自己即可,无需CAS或其他同步。
->什么时候会变成轻量级锁呢?
如果有另一个线程也尝试访问该对象,偏向锁会被撤销,进入轻量级锁阶段。
三、轻量级锁(Lightweight Lock)
轻量级锁是为了优化低竞争场景下的性能开销。
它通过CAS(Compare-And-Swap)操作,避免线程挂起和唤醒。
加锁流程:
线程在自己的栈帧中创建锁记录(Lock Record)。
尝试通过CAS,将对象头Mark Word指向自己的锁记录。
成功 → 轻松拿到锁。
失败(有竞争) → 可能膨胀为重量级锁。
解锁流程:
使用CAS把对象头恢复到原状态。
如果在锁期间没有其他线程参与竞争,解锁非常快。
四、重量级锁(Heavyweight Lock)
重量级锁是最传统、最可靠的锁机制,也叫做Monitor锁。
一旦竞争激烈,轻量级锁无法维持,就会膨胀成重量级锁。
加锁流程:
线程在获取锁失败后,挂起自己,进入阻塞状态。
等待持有锁的线程释放后,再重新被唤醒,竞争锁资源。
最后附上一张图,锁的升级流程