在 Java synchronized keyword 实现原理 中提到和 synchronized 关键字相关的锁有
- 偏斜锁
- 轻量级锁
- 重量级锁
各自适用的场景:
- 偏向锁,只有一个线程,无竞争环境
- 轻量级锁,多个线程交替进入,自旋加等待,无需上下文切换,轻微竞争环境
- 重量级锁,多个线程同时进入
偏向锁和轻量级锁都是 JVM 优化锁而引入的方法,目的是降低线程同步的开销。
一个对象在从无锁到重量级锁的过程如下。
线程访问对象:
- 检查对象头
Mark Word的线程 ID - 如果为空,在设置 CAS 替换为当前线程 ID,替换成功则获取成功,如果失败则撤销偏向锁
- 不为空,检查是否为当前线程,如果是则获取锁成功,失败则撤销偏向锁
升级为轻量级锁
轻量级锁不需要申请互斥量,仅仅将 Mark Word 中部分字段更新指向线程栈中的 Lock Record,如果更新成功就获取轻量级锁成功。记录锁状态为轻量级锁;否则,说明已经有其他线程获得了轻量级锁,升级为重量级锁。
在多个线程竞争时:
-
JVM 在当前线程栈帧中创建 Lock Record,并将对象头中的 Mark Word复制到 Lock Record 中
-
线程尝试使用 CAS 将对象头的 Mark Word 替换为指向 Lock Record 的指针。如果成功则获取锁,失败则先检查对象 Mark Word 是否指向当前线程栈帧,是,则获取锁,否则说明其他线程竞争锁,则膨胀为重量级锁。
-
偏斜锁,一个线程执行同步资源时,自动获取资源。指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价。
-
轻量锁,多个线程竞争同步资源时,没有获取资源的线程自旋等待锁释放,当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。
-
重量锁,多个线程竞争同步资源时,没有获取资源的线程阻塞等待唤醒。指当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。