本文持续更新,目前 JDK版本为 8
HotSpot 基础信息(x86 64位)
-
对象结构 (参考资料: https://weekly-geekly.github.io/articles/447848/index.html )
在 Hotspot 中一个对象由四部分数据组成。
① mark word (对象加锁后状态的变化就表现在这里面,下面的结构不确定)
- identity_hashcode 值 31bit
- GC 分代年龄 4 bit
- biased_lock 1bit lock 2bit
② class pointer (类型指针)
- 指向类的metadata
③ 实例数据
④ padding (位填充,使得对象的大小为8 byte的倍数)
1. 按8字节对齐
数组有一个额外的32bit 来描述它的长度信息,下面引用自 Hotspot jdk8源码 markOop.hpp
// 32 bits: // -------- // hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object) // JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object) // size:32 ------------------------------------------>| (CMS free block) // PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object) // // 64 bits: // -------- // unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2 (normal object) // JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object) // PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object) // size:64 ----------------------------------------------------->| (CMS free block)
锁基础信息
-
锁分类
- 无锁,表现在对象的 markword 标记位的后三位,最后两位锁标志位为 01,倒数第三位偏向锁位为0
- 偏向锁,只偏向于某个线程的锁即为偏向锁。 最后两位锁标志位为 01,倒数第三位偏向锁位为0。 当有2个线程及以上竞争时就会升级为轻量锁。在 Hotspot 中为默认开启(UseBiasedLocking)。但会有4秒延迟(BiasedLockingStartupDelay).
- 轻量锁, 大于两个线程小于系统cpu核数/2的线程数竞争会处在这个阶段,cas 实现,锁标志位 00
- 重量锁,会调用 os 的锁机制来实现,所以效率比较低下,锁标志位 10
-
锁升级过程
Hotspot启动默认开启了偏向锁开关,虽然偏向锁只对单个线程有用,看起来和无锁差不多,但是由于jvm的实现大部分都包含有同步的方法,在日常使用过程中,这些方法只会被同一个线程使用,就不需要重量级锁的实现了,所以加了这个偏向锁。默认开启了4秒延迟。这是由于应用场景的约束,
Synchronized
使用方法: 锁住这个对象的指定代码块,同一时间只能有一个线程执行这个代码块中的方法。这并不意味这同时只能有一个线程进入这个代码块,而是执行这个代码块的方法。
// DCL 经典代码, 和 volatile 配合使用更安全(静止指令重排序)
example-1:
if (multiDemo == null) {
synchronized (MultiDemo.class) {
if (multiDemo == null) { // 如果不加这个判断,实现不了单例。
multiDemo = new MultiDemo();
}
}
}
example-2:
代码分析:
网友评论