偏向锁、轻量锁升级对对象头、哈希码的影响

对象头:首先对象头分为两个部分,第一个部分是用于储存对象自身运行时数据(如哈希码,GC分代年龄),另一部分用于储存它的指向方法区的对象类型数据的指针。而实现偏向锁和轻量锁要用到第一部分,也叫MarkWord。


偏向锁:首先,是否使用偏向锁可以通过JVM参数进行设置-XX:+UseBiased Locking。当偏向锁启用的情况下,当线程第一次获取对象锁时,先将对象头的偏向模式和标志位设置为1、01,并且将当前线程ID写入MarkWord中。如果当前线程再次获取当前锁对象(例如进入使用该锁的同步块时),则不需要加锁解锁便可以使用。假如有其他线程尝试获得该对象锁,那么流程如下:如果该对象正在锁定状态(应该是判断MarkWord是否未锁定),偏向锁将直接升级成轻量锁,MarkWord会按照轻量锁规则进行变更。如果对象未锁定,那么偏向状态取消,对象成为不可偏向的对象,也就是只能使用轻量锁和重量锁了。


轻量锁:轻量锁的使用分为偏向锁的升级和不可用偏向锁的加锁。使用轻量锁,首先会将MarkWord进行一个拷贝储存在当前线程的栈帧中(一个叫做LockRecord的空间),然后对象头的MarkWord将通过CAS操作修改为指向锁记录的指针,而标志位将保留。如果CAS操作失败了,说明有一条线程与当前线程竞争锁,这时候会检查锁记录所在的栈,是否属于当前线程。如果相同,那么说明锁是当前线程加的,可以继续同步;如果是另一个线程,那么就出现了竞争,轻量锁将会膨胀成重量锁,线程将重新等待锁。


重量锁:当轻量锁膨胀成重量锁时,MarkWord将储存指向重量级锁(ObjectMonitor对象,保存MarkWord)的指针。


HashCode的问题:既然对象头MarkWord会占用HashCode空间,那么锁偏向后该如何安放呢?首先偏向锁是不会像轻量锁、重量锁那样用额外空间保存HashCode的。对于一个对象,其HashCode只会生成一次并保存,当对象处于可偏向(也就是线程ID为0)和已偏向的状态下,调用HashCode计算将会使对象再也无法偏向:当对象可偏向时,MarkWord将变成未锁定状态,并只能升级成轻量锁;当对象正处于偏向锁时,调用HashCode将使偏向锁强制升级成重量锁。

你可能感兴趣的:(偏向锁、轻量锁升级对对象头、哈希码的影响)