在JDK1.6之后,synchronized引入了无锁、偏向锁、轻量锁、重量锁的不可逆状态升级过程,以提高锁的获取和释放效率。
四种状态锁对象的对象头以及升级过程
- 最开始锁对象处于无锁状态,当初次执行到synchronized代码块的时候,锁对象变为偏向锁。此时通过cas修改偏向锁标志为1以及mark word改为偏向线程id
- 之后当锁对象被其他线程所访问,升级到轻量级锁,其他线程通过自旋的方式获取锁。此时锁标志位改为00,锁对象头除锁标志外的62bit由竞争成功线程栈记录地址指针所替代。
- 最后当某个线程自旋次数超过限度(默认为10),那么就由该线程将锁升级为重量级锁,未占有锁对象的线程进入等待队列。此时锁标志位改为10,mark word改为占有该锁的线程对该锁对象对应的重量级锁Monitor的指针
无锁
无锁是指不对资源进行锁定,所有线程都能访问到资源,但只有一个线程能够修改成功。
偏向锁
为什么引入偏向锁
HotSpot作者研究发现,多数情况下其实并不存在锁竞争,常常是一个线程多此获得同一个锁,所以为了降低锁获取代价,于是引入。
也可以通过虚拟机参数-XX:-UseBiasedLocking = false取消偏向锁
获取
线程B比较自己的threadId以及锁对象头threadId是否一致,若一致,则直接获取锁对象,无需使用cas加解锁。若不一致,则查看锁对象头中占有线程A是否存活,若不存活,则未占有线程竞争。若存活,进一步查看占有线程A是否需要继续持有,若需要继续持有,则暂停该线程,升级为轻量级锁,若不继续持有,为占有线程竞争。
轻量级锁
为什么引入
轻量锁考虑的是竞争锁线程不多而且持有锁时间也不长的情况。
重量级锁
重量级锁锁对象头引入了Monitor对象或者说同步工具。
Monitor是线程私有的数据结构,每一个线程都有一个monitor record列表,线程中每一个锁住的对象都有对应的monitor,并且在monitor中有一个owner字段标识着拥有该锁线程。
monitor线程同步是依赖于底层操作系统的mutex lock来实现同步。
Ref
- https://segmentfault.com/a/1190000022904663
- https://blog.csdn.net/tongdanping/article/details/79647337