说一说synchronized的实现原理
对象头、锁升级
标准回答
synchronized的底层是采用Java对象头来存储锁信息的,并且还支持锁升级。
Java对象头包含三部分,分别是Mark Word、Class Metadata Address、Array length。其中,Mark Word用来存储对象的hashCode及锁信息,Class Metadata Address用来存储对象类型的指针,而Array length则用来存储数组对象的长度。如果对象不是数组类型,则没有Array length信息。synchronized的锁信息包括锁的标志和锁的状态,这些信息都存放在对象头的Mark Word这一部分。
Java 6为了减少获取锁和释放锁带来的性能消耗,引入了偏向锁和轻量级锁。所以,在Java 6中,锁一共被分为4种状态,级别由低到高依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。随着线程竞争情况的升级,锁的状态会从无锁状态逐步升级到重量级锁状态。锁可以升级却不能降级,这种只能升不能降的策略,是为了提高效率。
synchronized的早期设计并不包含锁升级机制,所以性能较差,那个时候只有无锁和有锁之分。是为了提升性能才引入了偏向锁和轻量级锁,所以需要重点关注这两种状态的原理,以及它们的区别。
偏向锁,顾名思义就是锁偏向于某一个线程。当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程再进入和退出同步块时就不需要做加锁和解锁操作了,只需要简单地测试一下Mark Word里是否存储着自己的线程ID即可。
轻量级锁,就是加锁时JVM先在当前线程栈帧中创建用于存储锁记录的空间,并将Mark Word复制到锁记录中,官方称之为Displaced Mark Word。然后线程尝试以CAS方式将Mark Word替换为指向锁记录的指针,如果成功则当前线程获得锁,如果失败则表示其他线程竞争锁,此时当前线程就会通过自旋来尝试获取锁。
加分回答
下面,我们再从实际场景出发,来具体说说锁升级的过程。
总之,在锁升级的机制下,锁不会一步到位变为重量级锁,而是根据竞争的情况逐步升级的。当竞争小的时候,只需以较小的代价加锁,直到竞争加剧,才使用重量级锁,从而减小了加锁带来的开销。
Java对象头结构如下所示:
Mark Word默认结构如下所示(32位):
Mark Word在锁升级中演化结构如下所示(32位):
升级偏向锁的过程如下图:
升级轻量级锁的过程如下图:
得分点
对象头、锁升级
参考答案
标准回答
synchronized的底层是采用Java对象头来存储锁信息的,并且还支持锁升级。
Java对象头包含三部分,分别是Mark Word、Class Metadata Address、Array length。其中,Mark Word用来存储对象的hashCode及锁信息,Class Metadata Address用来存储对象类型的指针,而Array length则用来存储数组对象的长度。如果对象不是数组类型,则没有Array length信息。synchronized的锁信息包括锁的标志和锁的状态,这些信息都存放在对象头的Mark Word这一部分。
Java 6为了减少获取锁和释放锁带来的性能消耗,引入了偏向锁和轻量级锁。所以,在Java 6中,锁一共被分为4种状态,级别由低到高依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。随着线程竞争情况的升级,锁的状态会从无锁状态逐步升级到重量级锁状态。锁可以升级却不能降级,这种只能升不能降的策略,是为了提高效率。
synchronized的早期设计并不包含锁升级机制,所以性能较差,那个时候只有无锁和有锁之分。是为了提升性能才引入了偏向锁和轻量级锁,所以需要重点关注这两种状态的原理,以及它们的区别。
偏向锁,顾名思义就是锁偏向于某一个线程。当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程再进入和退出同步块时就不需要做加锁和解锁操作了,只需要简单地测试一下Mark Word里是否存储着自己的线程ID即可。
轻量级锁,就是加锁时JVM先在当前线程栈帧中创建用于存储锁记录的空间,并将Mark Word复制到锁记录中,官方称之为Displaced Mark Word。然后线程尝试以CAS方式将Mark Word替换为指向锁记录的指针,如果成功则当前线程获得锁,如果失败则表示其他线程竞争锁,此时当前线程就会通过自旋来尝试获取锁。
加分回答
下面,我们再从实际场景出发,来具体说说锁升级的过程。
总之,在锁升级的机制下,锁不会一步到位变为重量级锁,而是根据竞争的情况逐步升级的。当竞争小的时候,只需以较小的代价加锁,直到竞争加剧,才使用重量级锁,从而减小了加锁带来的开销。
延伸阅读
Java对象头结构如下所示:
Mark Word默认结构如下所示(32位):
Mark Word在锁升级中演化结构如下所示(32位):
升级偏向锁的过程如下图:
升级轻量级锁的过程如下图: