【jvm jdk】锁状态位之偏向锁

文章目录

  • 第一次验证
  • 第二次验证
  • 总结

相关文章:
锁状态位之无锁
锁状态位之偏向锁
锁状态位之轻量级锁
锁状态位之重量级锁

第一次验证

【jvm jdk】锁状态位之偏向锁_第1张图片
我们创建一个对象,没有上锁,然后再上锁,来观察锁标识位:

由于只有一个线程加锁,没有产生,所以预期是加偏向锁

public class Test {

    public static void main(String[] args) throws InterruptedException {
        //TimeUnit.SECONDS.sleep(5);  代码很重要,先注释掉,后面需要放开

        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());  //第一次打印,此时无锁

        synchronized (o){
            System.out.println(ClassLayout.parseInstance(o).toPrintable());  //第二次打印,此时有锁
        }
    }
}

执行结果:


java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 f3 27 (11100101 00000001 11110011 00100111) (670237157)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           88 f8 98 02 (10001000 11111000 10011000 00000010) (43579528)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 f3 27 (11100101 00000001 11110011 00100111) (670237157)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total


Process finished with exit code 0

分析:

第一条是001无锁的,和锁状态位之无锁中第一章节内容相同,主要看第二条打印:
在这里插入图片描述

注意字节是反序的:88 f8 98 02 (10001000第四个字节 11111000第三个字节 10011000第二个字节 00000010第一个字节)

我们发现第二条打印结果是轻量级锁,不是预期的偏向锁

那么为什么呢?
虽然默认开启偏向锁,但JVM会延迟去启动偏向锁,延迟大约三四秒,此时对于系统的前几秒来说,等价于没有开启偏向锁,解决方案有2种:

  • 加sleep 5s再试,放开代码中的语句块
    TimeUnit.SECONDS.sleep(5);
    
  • 关闭延迟开启偏向锁
    -XX:BiasedLockingStartupDelay=0

对于第二条语句来说,等价于 无锁 ->加轻量级锁(单线程加锁,低竞争度)

第二次验证

加了延迟后,对于第二条语句来说,等价于 无锁 ->延迟3后启动偏向锁(偏向线程ID为空) ->偏向锁,设置偏向线程ID为当前线程id


java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 21 f3 27 (11100101 00100001 11110011 00100111) (670245349)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           05 a8 5c 02 (00000101 10101000 01011100 00000010) (39626757)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 21 f3 27 (11100101 00100001 11110011 00100111) (670245349)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total


Process finished with exit code 0

第一条显示偏向锁,但是偏向线程ID为空

jdk1.8时,默认开启偏向锁,创建一个对象的话(在真正开启偏向锁之后才创建的对象), 对象会是可偏向状态,即锁的标识显示是偏向锁,但是偏向线程ID为空,等到后续真的发生需要加偏向锁时,会仅修改偏向线程ID即可。

第二条显示偏向锁,偏向线程ID为当前线程id

总结

对于单线程,低竞争度的锁来说,不是一定加轻量级锁,而是偏向锁的+线程id 来过度的,当然,需要jvm一定时间去开启,需要等待几秒钟

参考:
《禁止延迟开启偏向锁jvm参数》

你可能感兴趣的:(Java,偏向锁)