锁升级

java --XX:+PrintCommandLineFlags -version

普通对象 Objetct object = new Object() 16字节 (8+4+pending)

1 对象头 markword 8个字节

2 ClassPoint 指针 -XX:+UseCompressedClassPointers 为4字节 不开启 8字节

3 实例数据 引用类型 -XX:+UseCompressedOops 为4字节 不开启8字节

4 数据对齐 8的倍数


数组对象 16字节 (8+4+4)
1对象头 markword 8个字节

2 ClassPoint 指针 -XX:+UseCompressedClassPointers 为4字节 不开启8字节

3 数组长度 :4字节

4 数组数据

5 数据对齐 8的倍数


jvm -XX:-UseCompressedClassPointers 不在压缩 普通对象( 8+8)=16字节 数组 (8 +8 +4+pengding) =24字节


-XX:+UseCompressedOops 默认是打开的 引用类型 不开启8 字节 开启了4字节 默认开启 String 引用 Object引用 都是引用类型


对象头包括什么

markword MarkOop.hpp

锁标志位 是否偏向锁 分代年龄 对象的hashcode (new 无锁态 偏向锁 轻量级锁 重量级锁)
偏向锁 轻量级锁 都在用户空间完成 重量级锁 像内核申请
第一个线程过来了 偏向锁

轻量级锁 多个线程来竞争 有人来竞争锁了 先把偏向锁撤销 线程进行竞争 自旋竞争 多个线程自旋竞争
每个线程都有自己的线程栈 线程开始竞争 每个线程在线程栈内部生成一个LockRecord
自旋 每个线程争抢的方式 就是自旋 想办法把自己的LockRecord指针设置上去 指向哪个线程的LockRecord 哪个线程就拥有了锁
其它线程就用户空间自旋转圈 自旋转圈 直到其它线程执行完 释放了锁


字节码层面
同步代码块 monitorenter monitorexit monitorexit(异常)
同步方法 acc_synchronized

无锁态 hashcode identityhashcode

如果有锁了 hashcode存储到LockRecord 每个偏向锁都有一个LockRecord

重量级锁 记录在ObjectMonitor的_owner上面 ObjectMonitor 线程是wait状态 进入_WaitSet集合 _EntryList 新线程进来尝试获取锁对象 又没有获取到对象的时候 则会存进来

轻量级锁 升级为重量级锁 线程自旋超过10次 或者自旋线程数超过CPU核数的一半 1.6之后 加入了自适应自旋 自旋是消耗CPU的

升级为重量级锁 得向内核申请资源 ObjectMonitor waitset集合 里面全部都是wait的线程

想象一下 如果轻量级锁的自旋的线程很多 CPU消耗资源很大 把这些线程都丢到waitset集合 不消耗CPU时间 通过操作线程的调度
从集合里拿出来 等待队列 所有拿不到锁的进入等待队列 不需要消耗CPU了


偏向锁是否一定比轻量级锁好 不是 在知道有很多线程竞争的情况下还用偏向锁 没有必要 因为偏向锁 还需要锁撤销 浪费时间 应该直接关闭偏向锁

JVM默认启动的时候是不打开偏向锁的 过一段时间在打开 默认时候 偏向锁有延迟 4秒 -XX:BiasedLockingStartupDelay=0(启动就打开偏向锁)

就是启动4秒后就可以成偏向锁状态 匿名偏向 因为这个时候线程的ID还没有 (偏向锁未启动 普通对象)

posted @ 2020-08-01 20:00  沙漠里的小鱼  阅读(115)  评论(0编辑  收藏  举报