面试官synchronized连环问,学会Monitor之后轻松拿下

简介: 面试官synchronized连环问,学会Monitor之后轻松拿下

备战2022春招或暑期实习,祝大家每天进步亿点点!Java并发编程Day7

本篇总结的是 如何在Java中避免创建不必要的对象,后续会每日更新~

关于《我们一起学Redis》、《我们一起学HarmonyOS》等知识点可以查看我的往期博客

相信自己,越活越坚强,活着就该逢山开路,遇水架桥!生活,你给我压力,我还你奇迹!image.png目录


1、简介


2、对象头


3、Mark Word


4、Monitor


5、monitorente && monitorexit


1、简介

我们Java程序员编码时谈论的最多的两个字就是对象,Java中几乎所有的技术都是围绕对象展开。本文将要讲述的Monitor并不是Java对象,而是在操作系统中关联的“对象”,Monitor是Java重量级锁synchronized实现的关键,因此学习Java单机同步机制就离不开对Monitor的剖析。Monitor经常被人们称为监视器锁和管程。


2、对象头

Monitor与Java对象头相关联,因此剖析Monitor之前必须了解Java对象的组成结构。Java对象在内存中由三部分组成,分别是对象头、实例数据、对齐填充。以32位虚拟机为例(64位不同),对象头(Header)占8个字节共64位(数组对象头与普通对象头不同,数组对象头12个字节共96位);实例数据(Instance Data)存储这对象的实际数据,因此大小与实际数据大小一致;对齐填充(Padding)是可选项,用于将内存对齐为8字节的整数倍。


普通对象内存组成image.png如上两张图展示了Java对象内存结构,本文说的Monitor和这个有啥关系呢?其实对象头(Header)中的Mark Word就是用来存放Monitor对象的指针的,在一开始小捌就说了Monitor并不是Java对象,而是在操作系统中关联的“对象”,因此Java对象如果想要和Monitor进行关联,就必须在Java对象中记录Monitor的内存地址,这样才能通过Java对象找到这个Monitor嘛!


注:Klass Word存放的是指向对象对应的Class对象的指针。


3、Mark Word

可想而知,想要深入探讨Monitor肯定避不开Mark Word,这个时候暴躁的程序员小哥肯定不爽了,你特么不是说Mark Word中存放的Monitor的内存地址么,我知道了啊……

别急,并不是想的那样的,这里稍微有一丢丢复杂,听我慢慢道来。

Java对象在不同的状态下,Mark Word存储的值完全不同,尤其是在JDK1.6对锁优化之后,Mark Word这32bits内存空间,真的是被Java大师们压榨到了极致。了解这个需要有一定的JVM和synchronized知识,如果不懂的话也无所谓,先了解就好,后面我们一起学习synchronized锁升级过程。


初始状态下Java对象头的Mark Word里默认存储的是对象的hashcode、GC分代年龄、是否偏向锁和锁标志位

image.png4、Monitor

上面铺垫了这么多东西,其实就是为了讲述Monitor和Java对象头中Mark Word的关系,可以看出来只有在重量级锁的情况下Java对象头中Mark Word才会关联一个Monitor对象,那么Monitor又是个什么东西呢?我相信你一定很好奇吧!


Monitor内部分由三部分组成分别是Owner、EntryList、WaitSet;


Owner用于记录当前Monitor的所属线程

EntryList是一个链表结构,用于记录阻塞在当前锁对象上的线程

WaitSet用于记录获取锁之后进入Waiting状态的线程image.png当对象获取到锁之后,由于某些资源并未准备完成,需要等待其他线程去准备资源,此时线程会通过wait()/notify()等方法进入等待/通知模式,在这种情况下线程释放锁之后会进入WaitSet,当其他线程准备好资源之后会通知WaitSet中等待的线程,WaitSet中的线程会进入到EntryList中,重新参与锁竞争。

————————————————

版权声明:本文为CSDN博主「李子捌」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qq_41125219/article/details/121687007image.png5、monitorente && monitorexit

知道了Monitor是什么,也知道了Java对象与Monitor之间的关系,但是还有一层疑问;程序在运行过程中是如何知道要给Java对象去关联一个Monitor呢?

这就需要一点点Java字节码相关的知识了,Java的源代码在编译器编译之后生成的Class文件中存储的是字节码指令,程序执行本质上是一条条指令按照既定顺序的流水线工作,那这只有一种可能了,编译器在编译成Java字节码时做了记号,这个记号就是monitorente /monitorexit。


我们先来看一段简单的synchronized代码块:

image.pngimage.pngimage.png

 0 getstatic #2 <com/lzb/concurrency/demo2/MonitorDemo.LOCK : Ljava/lang/Object;>
 3 dup            
 4 astore_1
 5 monitorenter
 6 getstatic #3 <com/lzb/concurrency/demo2/MonitorDemo.count : I>
 9 iconst_1
10 iadd
11 putstatic #3 <com/lzb/concurrency/demo2/MonitorDemo.count : I>
14 aload_1
15 monitorexit
16 goto 24 (+8)
19 astore_2
20 aload_1
21 monitorexit
22 aload_2
23 athrow
24 return

前三行字节码分别表示:

  • getstatic 获取静态锁对象LOCK
  • dup 复制一份LOCK对象的引用,用于锁退出
  • astore_1 复制的引用存入临时变量1中 3 dup reference -> slot 1image.pngsynchronized临界区七行字节码分别表示:


monitorenter 关联一个操作系统Monitor对象,替换LOCK对象的Mark Word为Monitor地址

getstatic 获取静态变量count

iadd count++操作

putstatic 赋值++操作后的count

aload_1 获取LOCK对象的引用,上面dup复制后astore_1 指令存储的那份地址

monitorexit 还原Mark Word,将Monitor对象指针替换为monitorenter 加锁时保存在Monitor对象中的数据,如hashcode、分代年龄等数据;同时唤醒等待在EntryList中阻塞等待的线程。image.png异常表中有两行记录:


第一行表示:6 -> 16行字节码中发生了异常,会跳转到19行,这就是synchronized加锁的代码区域,如果加锁中出现异常,JVM会处理异常,正确释放锁

第二行表示:19 -> 22行字节码中发生了异常,会跳转到19行,

未发生异常情况:


goto 24 (+8) 没有产生异常,直接执行24行指令

return 方法运行结束image.png发生异常情况:


astore_2 将异常对象存储到临时变量中 e -> slot 2

aload_1 加载LOCK锁对象引用地址

monitorexit 还原Mark Word,将Monitor对象指针替换为monitorenter 加锁时保存在Monitor对象中的数据,如hashcode、分代年龄等数据;同时唤醒等待在EntryList中阻塞等待的线程。

aload_2 加载异常对象

athrow 抛出异常对象

return 方法运行结束image.png


image.png


image.png


image.png

目录
相关文章
|
6月前
|
存储 Java 开发者
面试官:小伙子知道synchronized的优化过程吗?我:嘚吧嘚吧嘚,面试官:出去!
面试官:小伙子知道synchronized的优化过程吗?我:嘚吧嘚吧嘚,面试官:出去!
72 1
|
6月前
|
Java
【面试问题】Synchronized 和 ReentrantLock 区别?
【1月更文挑战第27天】【面试问题】Synchronized 和 ReentrantLock 区别?
|
8天前
|
存储 安全 Java
面试高频:Synchronized 原理,建议收藏备用 !
本文详解Synchronized原理,包括其作用、使用方式、底层实现及锁升级机制。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
面试高频:Synchronized 原理,建议收藏备用 !
|
4月前
|
缓存 安全 算法
Java面试题:如何通过JVM参数调整GC行为以优化应用性能?如何使用synchronized和volatile关键字解决并发问题?如何使用ConcurrentHashMap实现线程安全的缓存?
Java面试题:如何通过JVM参数调整GC行为以优化应用性能?如何使用synchronized和volatile关键字解决并发问题?如何使用ConcurrentHashMap实现线程安全的缓存?
45 0
|
1月前
|
存储 安全 Java
面试题:再谈Synchronized实现原理!
面试题:再谈Synchronized实现原理!
|
3月前
|
存储 安全 Java
【多线程面试题十七】、如果不使用synchronized和Lock,如何保证线程安全?
这篇文章探讨了在不使用`synchronized`和`Lock`的情况下保证线程安全的方法,包括使用`volatile`关键字、原子变量、线程本地存储(`ThreadLocal`)以及设计不可变对象。
|
3月前
|
Java
【多线程面试题十五】、synchronized可以修饰静态方法和静态代码块吗?
这篇文章讨论了Java中的`synchronized`关键字是否可以修饰静态方法和静态代码块,指出`synchronized`可以修饰静态方法,创建一个类全局锁,但不能修饰静态代码块。
|
3月前
|
Java 调度
【多线程面试题十四】、说一说synchronized的底层实现原理
这篇文章解释了Java中的`synchronized`关键字的底层实现原理,包括它在代码块和方法同步中的实现方式,以及通过`monitorenter`和`monitorexit`指令以及`ACC_SYNCHRONIZED`访问标志来控制线程同步和锁的获取与释放。
|
3月前
|
Java
【多线程面试题十三】、说一说synchronized与Lock的区别
这篇文章讨论了Java中`synchronized`和`Lock`接口在多线程编程中的区别,包括它们在实现、使用、锁的释放、超时设置、锁状态查询以及锁的属性等方面的不同点。
|
4月前
|
安全 Java
Java面试题:解释synchronized关键字在Java内存模型中的语义
Java面试题:解释synchronized关键字在Java内存模型中的语义
46 1