【JUC学习笔记——共享模型之管程】首先我们回忆一下对象头格式:
|--------------------------------------------------------------------|--------------------||Mark Word (64 bits)|State||--------------------------------------------------------------------|--------------------|| unused:25 | hashcode:31 | unused:1 | age:4 | biased_lock:0 |01|Normal||--------------------------------------------------------------------|--------------------|| thread:54 |epoch:2| unused:1 | age:4 | biased_lock:1 |01|Biased||--------------------------------------------------------------------|--------------------||ptr_to_lock_record:62|00| Lightweight Locked ||--------------------------------------------------------------------|--------------------||ptr_to_heavyweight_monitor:62|10| Heavyweight Locked ||--------------------------------------------------------------------|--------------------|||11|Marked for GC||--------------------------------------------------------------------|--------------------|
我们进行简单解释:
- Normal:正常锁
- Biased:正常偏向锁
- Lightweight Locked :轻量级锁
- Heavyweight Locked:重量级锁
- biased_lock : 控制偏向锁的开启的码位
- 如果开启了偏向锁(默认开启)那么对象创建后,markword值为0x05即最后3位为101,这时它的 thread、epoch、age 都为 0
- 偏向锁是默认是延迟的,不会在程序启动时立即生效
- 如果想避免延迟,可以加 VM 参数- XX:BiasedLockingStartupDelay=0来禁用延迟
- 如果没有开启偏向锁,那么对象创建后,markword 值为 0x01 即最后 3 位为 001
- 这时它的 hashcode、 age 都为 0,第一次用到 hashcode 时才会赋值
- 但是如果调用了hashcode方法就会导致覆盖掉biased_lock关闭偏向锁
撤销 - 调用对象 hashCode我们给出简单解释:
- hashcode与biased_lock的字节码位置冲突,若调用hashcode方法得到hashcode就会覆盖掉biased_lock位置,导致偏向锁失效
- 调用了对象的hashCode,但偏向锁的对象MarkWord中存储的是线程 id,如果调用hashCode会导致偏向锁被 撤销
- 轻量级锁会在锁记录中记录 hashCode
- 重量级锁会在 Monitor 中记录 hashCode
- 当有其它线程使用偏向锁对象时,会将偏向锁升级为轻量级锁
/*主代码*/private static void test2() throws InterruptedException {Dog d = new Dog();Thread t1 = new Thread(() -> {synchronized (d) {log.debug(ClassLayout.parseInstance(d).toPrintableSimple(true));}synchronized (TestBiased.class) {TestBiased.class.notify();}// 如果不用 wait/notify 使用 join 必须打开下面的注释// 因为:t1 线程不能结束,否则底层线程可能被 jvm 重用作为 t2 线程,底层线程 id 是一样的/*try {System.in.read();} catch (IOException e) {e.printStackTrace();}*/}, "t1");t1.start();Thread t2 = new Thread(() -> {synchronized (TestBiased.class) {try {TestBiased.class.wait();} catch (InterruptedException e) {e.printStackTrace();}}log.debug(ClassLayout.parseInstance(d).toPrintableSimple(true));synchronized (d) {log.debug(ClassLayout.parseInstance(d).toPrintableSimple(true));}log.debug(ClassLayout.parseInstance(d).toPrintableSimple(true));}, "t2");t2.start();}/*结果*/[t1] - 00000000 00000000 00000000 00000000 00011111 01000001 00010000 00000101[t2] - 00000000 00000000 00000000 00000000 00011111 01000001 00010000 00000101[t2] - 00000000 00000000 00000000 00000000 00011111 10110101 11110000 01000000[t2] - 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000001
撤销 - 调用 wait/notify我们进行简单解释:- wait和notify方法都是重量级锁的专属方法,如果调用就会导致升级为重量级锁
/*主代码*/public static void main(String[] args) throws InterruptedException {Dog d = new Dog();Thread t1 = new Thread(() -> {log.debug(ClassLayout.parseInstance(d).toPrintableSimple(true));synchronized (d) {log.debug(ClassLayout.parseInstance(d).toPrintableSimple(true));try {d.wait();} catch (InterruptedException e) {e.printStackTrace();}log.debug(ClassLayout.parseInstance(d).toPrintableSimple(true));}}, "t1");t1.start();new Thread(() -> {try {Thread.sleep(6000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (d) {log.debug("notify");d.notify();}}, "t2").start();}/*结果*/[t1] - 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000101[t1] - 00000000 00000000 00000000 00000000 00011111 10110011 11111000 00000101[t2] - notify[t1] - 00000000 00000000 00000000 00000000 00011100 11010100 00001101 11001010
批量重偏向我们先来介绍一下批量重偏向:
推荐阅读
- Seata Server 1.5.2 源码学习
- 2022极端高温!机器学习如何预测森林火灾?? 万物AI
- 1.nginx学习
- 常用Python库整理
- 图学习参考资料 词向量word2vec
- 五 RK3568开发笔记:在虚拟机上使用SDK编译制作uboot、kernel和ubuntu镜像
- realme笔记本最新消息_realme笔记本即将发布
- JUC学习笔记——进程与线程
- Seata 1.5.2 源码学习
- 第4版 高性能MySQL 第一章 MySQL架构 读书笔记