对象结构介绍
对象Object的结构分为三部分:对象头、实例数据以及填充字节
Mark Word 中存储当前对象运行时状态相关的数据(hashcode 、 锁状态标志等等)
class point 为指针,指向方法区中该对象对应的类的类型数据
填充字节 用来满足对象的大小必须是8bit的倍数这一要求
Mark Word介绍
Mark Word被设计的极小,通常为32bit/64bit
以下为Mark Word 的结构图
64位
32位
Synchronized 实现锁机制的原理:
synchrozied 关键字经过Javac编译后,会被编译成字节码指令monitorenter和monitorexit来完成锁机制。monitor为管程/监控器,而monitor的实现是依赖于操作系统的mutex lock 实现的,属于重量级锁
由于JDK1.6 之前,synchronized实现锁机制为重量级锁,线程的切换涉及到用户态和内核态的切换,效率较低,所以JDK1.6 提出了锁升级的概念。
锁升级
JDK1.6 之后,java中对象锁分为4种状态:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态
Java锁升级的过程:
无锁状态:
第一种情况:不存在竞争关系
第二种情况:存在竞争关系,但采用非锁的方式即CAS的方式解决
偏向锁:对某一个对象第一次上锁时,就是偏向锁,该对象的MarkWord中会存储该线程的ID,可以理解为对象锁认识该线程,可以获取到锁,当多个线程竞争该锁,就会进行锁升级,升为轻量级锁
轻量级锁:当锁升级为轻量级锁时,线程会在自己的虚拟机栈中开辟一块称为Lock Record的空间,lock record中会存储对象头中Mark Word的副本以及owner指针,线程会通过CAS尝试获得锁,一但获得锁,就会将Mark Word复制到lock record中,并将owner指针指向该对象,另一方面,该对象的Mark word中的指针会指向获得锁的线程的lock record,就完成了获得获取与绑定。其他的线程想要获取锁,会自旋等待。
自旋相当于CPU在空转,会浪费CPU的资源,所以产生了自适应自旋,也就是说自旋的时间不再固定,而是由上一次在同一个锁上自旋的时间和锁的状态共同决定。如果上一次自旋获得过锁,JVM就会认为有机会通过自旋获得锁,就会允许更长时间的自旋来获得锁。
重量级锁:如果线程长时间的自旋或等待的线程特别多,救护进行下一步的锁升级,也就是升级与重量级锁,通过操作系统来操作线程。JDK1.6规定的是,线程自旋10 次会升级为重量级锁,或等待线程的数量超过CPU合数的1/2,升级为重量级锁,这两个参数乐意通过JVM调优来设置,但目前JVM会自适应,有JVM来决定什么时候升级为重量级锁,不用调优啦。
JAVA中的锁分类:
参考的资料:
哔哩哔哩中寒食君课程:【Java并发】月薪30K必须知道的Java锁机制_哔哩哔哩_bilibili
哔哩哔哩中马士兵_马小安:深入P8级别JAVA架构师底层知识:无锁、偏向锁、轻量级锁、重量级锁升级过程_哔哩哔哩_bilibili