锁升级机制
- 简介
- 锁升级流程
- 三种锁的优缺点
简介
synchronized在早期被称为重量级锁,而到现在已经得到不少优化。偏向锁、轻量级锁、重量级锁指的是synchronized三种形态。
锁升级流程
无锁(Unlocked):
初始状态,表示对象没有被任何线程锁定。如果线程 A 想要获取这个对象的锁,它会将对象的状态从无锁状态升级为偏向锁状态。
偏向锁(Biased Locking):
当某个线程成功获取了对象的锁时,对象会进入偏向锁状态。在这个状态下,偏向于锁的线程可以连续多次获取锁而不触发同步,从而减少竞争。如果其他线程尝试获取这个锁,偏向锁会升级为轻量级锁状态。
偏向锁一般是针对于只有一个线程访问的情况,这种情况不会发生资源竞争,如果一直只有一个线程访问共享资源,每次访问都要进行获取锁和释放锁的操作,对性能的开销非常大。
而偏向锁的实现方式非常简单同时效率很高只需要在对象头中做一个是偏向锁的标记,然后存储线程ID代表这个资源被某个线程占有。
当这个线程再次访问这个资源的时候不需要进行加锁和释放锁的操作,直接可以访问资源。
线程访问的时候会对比Mark Word中的线程ID,如果匹配成功就直接访问资源,如果不匹配就去查看偏向锁标记位,看看是否标记有偏向锁(标志位是否为1),如果没有设置,则使用CAS竞争锁;如果设置了**,则尝试使用CAS将对象头的偏向锁指向当前线程,这时就发生了资源竞争,会升级为轻量级锁。**
轻量级锁(Lightweight Locking):
如果有多个线程尝试获取同一个锁,偏向锁会升级为轻量级锁。在轻量级锁状态下,锁会尝试使用CAS(Compare and Swap)操作来尝试获取锁,而不是阻塞线程。如果多个线程竞争激烈,轻量级锁可能会升级为重量级锁。
轻量级锁状态下线程会通过自旋的方式来尝试获取锁(在循环中tryLock),轻量级锁的自旋对cpu的损耗极大,当高并发场景下使用轻量级锁会严重损耗cpu性能。每增加一个线程,其他所有线程都要多自旋一次,开销极大。
如果多次尝试还无法获取锁,就会升级为重量级锁。
重量级锁(Heavyweight Locking):
当竞争非常激烈且无法通过轻量级锁解决时,锁会升级为重量级锁。这时候,其他线程会被阻塞,直到持有锁的线程释放锁。
进入重量级锁时,只有当前线程执行完所有操作后,通知阻塞队列中的线程后,阻塞队列中的线程才会被唤醒继续竞争。