这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战
引言
上一篇简单介绍了Java内置锁升级的过程,在讲述偏向锁升级为轻量级锁时一笔带过,本文意在通过画图的方式讲解偏向锁的原理。
当存在多个线程竞争同一个锁时,此锁已有偏向,其他线程发现偏向并不是偏向自己,就说明存在了竞争。尝试撤销偏向锁然后膨胀到轻量级锁。
偏向锁的撤销
偏向锁的撤销过程如下:
1.在一个安全点上停止拥有锁的线程
2.遍历线程的栈帧,检查其是否存在锁记录,如果存在锁记录将其清空,并修复存放线程ID的Mark Word,使对象变为无锁的状态。
3.将当前锁升级为轻量级锁,lock位变为00.
4.唤醒当前线程。
偏向锁的膨胀
如果偏向锁已被一个线程占有,其他线程在要占有该锁对象,因为偏向锁不会主动释放,所以JVM会先将偏向锁撤销,撤销后检查之前占有锁的线程是否存活(Mark Word中指向的线程),如果线程挂了,对象变为无锁状态,可重新进行偏向。
如果线程没挂,则膨胀为轻量级锁。
轻量级锁
抢占锁
抢锁线程进入临界区之前,会先在栈帧中创建一个lock record空间,复制一份锁对象的Mark Word保存起来,然后使用CAS(null, lock record地址)函数,将自己的Lock Record地址写到锁对象的Mark Word中,如果写入成功,则该线程占有轻量级锁成功,owner指向对象的地址。如写入失败,则循环尝试CAS。