synchronized连环问

synchronized是面试中经常会被问到的知识点,相关的问题点也很多,问题答案涉及的知识点也很多,有经验的面试官就会顺着你的答案不断追问一下,下面的对话场景就是相关面试题的连环炮。

面试官:说一下synchronized的作用。

小白:对于单一JVM来说,synchronized可以保证在并发情况下,同一时刻只有一个线程执行某个方法或某段代码,它可用于修饰方法或代码块,实现对同步代码的并发安全控制。

面试官:你刚刚说synchronized可用于修饰方法和代码块,他们有什么区别呢?

小白:修饰方法在底层实现上会在方法访问标识中设置ACC_SYNCHRONIZED标示符,修饰代码块在底层实现上会使用monitorenter和monitorexit指令。

面试官:那你说一下修饰方法方式的底层实现原理?

小白:反编译字节码文件,可以看到在方法的flags中设置了ACC_SYNCHRONIZED访问标识。每个对象都与一个monitor相关联,当且仅当monitor被线程持有时,monitor处于锁定状态。当方法执行时,线程将先尝试获取对象相关联的monitor所有权,然后再执行方法,最后在方法完成(无论是正常执行还是非正常执行)时释放monitor所有权。在方法执行期间,线程持有了monitor所有权,其它任何线程都无法再获得同一个对象相关联的monitor所有权。(这里的回答会引发面试官提问Java对象头和锁相关的问题,需要有心理准备。)

面试官:那你再说一下修饰代码块方式的底层实现原理?

小白:反编译字节码文件,可以看到在逻辑代码前添加了monitorenter指令,在逻辑代码尾添加了monitorexit指令。当方法执行时,当前线程执行monitorenter指令尝试获取对象相关联的monitor所有权时,如果此时这个monitor的计数器是0,那么当前线程持有该monitor,同时monitor计数器设置为1;如果当前线程已经持有了对象相关联的monitor所有权,只是想重新获取,那么继续持有该monitor,同时monitor计数器加1;如果有其它线程已经持有了对象相关联的monitor所有权,当前线程阻塞,直到monitor计数器为0,再次尝试获取所有权。方法正常执行或发生异常时,会执行monitorexit指令,释放monitor所有权,monitor计数器减1。

面试官:你刚刚说到了Monitor,能详细再说说吗?

小白:Java虚拟机中,synchronized支持的同步方法和同步语句都是使用monitor来实现的。每个对象都与一个monitor相关联,当一个线程执行到一个monitor监视下的代码块中的第一个指令时,该线程必须在引用的对象上获得一个锁,这个锁是monitor实现的。在HotSpot虚拟机中,monitor是由ObjectMonitor实现,使用C++编写实现,具体代码在HotSpot虚拟机源码ObjectMonitor.hpp文件中。

查看源码会发现,主要的属性有_count(记录该线程获取锁的次数)、_recursions(锁的重入次数)、_owner(指向持有ObjectMonitor对象的线程)、_WaitSet(处于wait状态的线程集合)、_EntryList(处于等待锁block状态的线程队列)。

当并发线程执行synchronized修饰的方法或语句块时,先进入_EntryList中,当某个线程获取到对象的monitor后,把monitor对象中的_owner变量设置为当前线程,同时monitor对象中的计数器_count加1,当前线程获取同步锁成功。

当synchronized修饰的方法或语句块中的线程调用wait()方法时,当前线程将释放持有的monitor对象,monitor对象中的_owner变量赋值为null,同时,monitor对象中的_count值减1,然后当前线程进入_WaitSet集合中等待被唤醒。

面试官:你的回答中说到了锁,那一个对象的锁状态存在哪里?

小白:Java对象的对象头中。

面试官:对象头中包含哪些内容?

小白:一部分是对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,官方称它为“Mark Word”;一部分是类型指针,即是对象指向它的类的元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例;如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中无法确定数组的大小。

面试官:相对于对象头中的锁状态标识来说,synchronized属于哪一级别的锁?

小白:重量级锁。

面试官:JVM对锁进行了哪些优化?

小白:......

这样的问答模式平时可以多练习练习,一个可以检查自己知识储备如何,另一个可以梳理知识脉络,从宏观上掌握技术的连通性,将知识串联起来,形成一套知识体系。

推荐阅读:

如有收获,请点击底部右下角"在看",谢谢!

640?wx_fmt=jpeg

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在面试中,有时会synchronized的优化题。synchronized是一种实现对象锁的方式,它可以确保多个线程在访共享资源时的互斥性,避免数据不一致的题。在早期的JDK版本中,synchronized的性能较差,原因主要有两个方面。首先,JDK 6以前的synchronized是基于重量级锁实现的,它使用操作系统的互斥量来实现线程的互斥访,需要进行用户态和内核态之间的切换,开销较大。其次,synchronized在锁竞争激烈的情况下,会导致线程频繁地进行阻塞和唤醒操作,增加了线程切换的次数,影响了系统的吞吐量。 为了对synchronized进行优化,JDK 6以后引入了轻量级锁和偏向锁的概念。轻量级锁使用CAS(Compare and Swap)操作来实现线程的互斥访,避免了用户态和内核态之间的切换,提升了性能。偏向锁则是在对象第一次被一个线程访时,将该线程的ID记录在对象头中,之后该线程再次访该对象时,无需进行同步操作,从而减少了锁的竞争,提高了性能。这些优化措施使得synchronized在并发场景下的性能得到了显著的提升。 总结起来,JDK 6以前synchronized的性能较差,主要是因为它使用了重量级锁,并且在锁竞争激烈的情况下会导致线程频繁阻塞和唤醒。而JDK 6以后引入了轻量级锁和偏向锁的优化机制,使得synchronized在并发场景下的性能得到了提升。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [【面试】Synchronized常见面试题](https://blog.csdn.net/HeavenDan/article/details/120776181)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值