怒刷牛客JAVA面经(3)

本文题目来自于牛客上面的面经分享,会贴上来源帖子
本次题目来源:感谢分享
个人想法,结合其他资料整理的,文章有问题希望大佬可以指出,目前正在准备春招,希望上岸🙏🏻

Spring的核心思想说说你的理解?IOC是什么?AOP是什么?有什么好处?

  第一和第二个问题应该是连在一起问的,所以放在一起回答
  Spring的核心思想无外乎就三个东西:IOC(控制反转)、AOP(面向切面编程)和DI(依赖注入),下面分别讲讲各自是什么

  • IOC(控制反转):全称Inversion of Control,从名字上来解析,就是将对象的控制权交给外部容器来管理对象之间的依赖关系,而不是对象之间自己维护,从而实现了松耦合和可维护性。
      举一个例子:A用户想要买B用户的商品,一般来说就是A用户直接线下找B用户购买,所有细则都是二者自己维护;IOC则类似于一个中间商,只要A有想要购买B商品的需求,直接找中间商就行,中间商再去找B购买,购买完以后再返还给A,期间A和B是不需要见面就能将商品购买的流程,所有操作都由中间商操作。
  • AOP(面向切面编程):全称 Aspect Oriented Programming,首先我们要知道什么是切面,切面指的是那些存在于应用程序多个模块中的功能,但是它们与核心业务逻辑并不直接相关,如日志记录、安全控制、事务管理等。虽然和业务无关,但是却十分重要的功能,我们就可以把他叫做切面。
      AOP则是将这些切面从业务代码中剥离出来,并尽可能地实现它们的重用和集中管理,以达到提高代码复用率,让程序员专注于业务代码的效果。
  • DI(依赖注入):全称Dependency Injection,控制反转是一种思想,而依赖注入是IOC的实现。在依赖注入中,对象的依赖关系不是在对象内部通过创建依赖对象的方式实现的,而是由外部容器负责创建和注入的。


我看你用了中间件,消息幂等了解吗?

  不清楚什么中间件,就直接讲消息幂等性了。
  消息幂等性是指在消息传输和处理过程中,无论消息被处理多少次,最终的结果都是一致的
  消息出现幂等性问题,无非就是生产端重复发送或者消费端重复消费了,从这两个方面去解决就能实现消息幂等性。
  生产端:每条数据都带上一个唯一ID,就算是业务代码中有重传机制,附带的ID也是需要重传的消息的ID。
  消费端:通过ID去判断消息是否被消费,一般是将消息ID放到redis中,然后判断是否重复,或者如果有涉及到消息ID存储到数据库中的情况,就在数据库中查找有无相关数据。


JVM内存模型?

  如果是讲的JVM内存区域的话,可以看之前写过的一篇面试题里面有详细的:面试1
  总结一下JVM内存区域划分:分为三个部分:内存共享、内存独占、直接内存。内存共享的叫堆,里面存放着所有对象的实例;内存共享区域主要是栈,线程每次调用方法都会产生一个栈帧用于存放调用方法所需要的数据,如过程中产生的数据,返回地址等;直接内存不被虚拟机管理,他是由操作系统管理,一般用于NIO操作,用来加快IO。

  下面讲的是JAVA内存模型,简称JMM(Java Memory Model):
  其实JMM是一种规范,他定义了 Java 程序中多线程并发访问共享内存时的行为方式。JMM主要关注于各种线程之间如何访问共享变量的规则,以及这些规则如何影响程序的正确性和性能,也是为了能过让Java具有跨平台性,不必在在意底层操作系统的内存模型。
  借用一下guide哥的图片:来源
在这里插入图片描述
  主要讲一讲两个东西,一个是共享变量的访问规则,一个是happens-before 关系。
  共享变量的访问规则主要有两点:

  • 所有变量都存储在主内存中,线程操作变量时必须先将变量从主内存拷贝到自己的工作内存中,然后对变量进行操作,最后将变量的值写回主内存
  • 如果一个变量是共享变量(被多个线程访问),那么每个线程在访问共享变量时都必须遵循一定的规则,以确保线程之间的可见性和正确性

  happens-before 关系则是 Java 内存模型中定义的一种规则,用于确定操作的执行顺序。如果操作 A happens-before 操作 B,也就是在操作B前A以及操作了,那么操作 A 的结果对操作 B 是可见的,并且操作 A 的执行顺序在操作 B 之前。
  总结一句话,JMM就是一种规范,规定了共享变量全部都存放到主内存中,线程不能直接操作变量,只能操作每个线程中的本地内存,而本地内存则是对主内存的一个副本。

JMM概念有点抽象,建议看看这篇文章:JMM概述



如何判断垃圾可以被回收?

之前的文章中有提到过垃圾回收相关的,可以看看之前的文章:面试1

  之前的文章⬆️讲过,这里就直接概括一下,判定垃圾可以被回收有两种方法:

  1. 引用计数法:每个对象都维护着一个引用计数器,当对象被引用时计数器加一,当对象的引用被释放时计数器减一;当计数器为0时,表示对象不再被引用,可以被回收。
  2. 可达性分析法:在可达性分析中,从一组称为“GC Roots”的对象出发,通过对象之间的引用关系,逐个标记所有能被引用到的对象,未被标记的对象即被判定为垃圾对象。


说说垃圾回收算法?

之前的文章中有提到过垃圾回收相关的,可以看看之前的文章:面试1

  之前的文章⬆️讲过,这里就直接概括一下,一共四种算法:

  1. 标记-清除法:分两个阶段:标记阶段,垃圾回收器会从根对象出发,遍历所有可达对象,并标记其为活动对象;清除阶段,垃圾回收器会清除未被标记的对象,但是会导致内存碎片化。
  2. 标记-整理法:与标记-清除算法类似,但在垃圾回收阶段会将存活的对象压缩到一端,从而减少内存碎片化。
  3. 复制算法:接将内存划分为两块,一次只用一块,另外一块用来垃圾回收了以后,将存活的对象连续存放,这样就可以保证内存使用是连续的了。
  4. 分代算法:分代算法根据对象的存活周期将堆内存划分为多个代,一般分为年轻代和老年代。年轻代使用复制算法进行垃圾回收,老年代使用标记-清除或标记-压缩算法进行垃圾回收。利用各个算法的优缺点给不同的代使用不同的算法,就是分代算法。


说说StackOverflowError和OutOfMemoryError产生的场景?

  下面从原因和场景两个点说说:

  1. StackOverflow:
    • 原因:从名字就知道,栈 溢出,也就是虚拟机栈深度超过了最大限制。
    • 场景:方法的递归调用层级过深或者无限循环导致的。
  2. OutOfMemoryError:
    • 原因:Java 虚拟机无法分配到足够的内存,也就是内存不够了。
    • 场景:
      1. 堆内存溢出:当创建的对象数量过多,超出了堆内存的最大限制时,就会导致堆内存溢出。
      2. 方法区(元空间)溢出:加载的类或者静态变量过多,就可能导致方法区溢出。

  总结就是,StackOverflow是和栈有关的,栈被用于线程的方法调用,OutOfMemory是和内存有关的,而堆区域是Java虚拟机内存最大的区域,它用于存放对象的实例,二者都是内存不足,只是作用范围不同。


项目中遇到过这种问题吗?怎么排查?

  对于StackOverflow来说还是比较好查的,一般都是递归调用导致的,只要找到报错的方法,查看代码导致的递归问题就行了,一般都是代码问题,如果不是代码问题,可以适当增加一下栈的内存大小,通过–Xss(size)来设置,例如-Xss256k。
  对于OutOfMemory,可以使用一些内存分析工具,如VisualVM,去查看内存使用情况,查看哪些对象占用内存较大,再去分析原因,是代码问题还是代码特性(业务问题,对象就是这么大)。


对于慢查询碰到过吗?说了不走索引,索引失效还有哪些?除了这个还有别的可能产生慢查询的原因吗?

  两个问题放一起,不清楚贴主当时的场景,就分析一下慢查询。
  慢查询,顾名思义,就是很慢的查询,产生的原因主要有以下几个:

  • 索引问题:要么就是对查询条件没设置索引,要么就是索引失效了,又或者是索引没有设计好产生了回表操作。
  • sql问题:过多的连表查询或子查询,会导致效率变低。
  • 查询数据过多
  • 锁机制:可能是死锁问题,或者是等待锁导致的慢查询。

  虽然贴主没被问到如何排查,这里也补充一下,排查的方法有以下几种可以参考:

  • 分析慢查询日志,找出具体的慢查询语句和原因。(慢查询日志可以看这篇文章:mysql进阶-查询优化-慢查询日志
  • 使用数据库性能分析工具来分析查询执行计划、索引使用情况等,例如我们在mysql中可以使用explain指令来查看执行计划。
  • 优化查询语句,避免复杂查询逻辑,合理使用索引,避免索引失效和回表操作。
  • 对于大数据量表,可以考虑数据分片、分区等方式来提高查询性能。

分库分表做过吗?为什么要分库分表?

  实话实说,我没做过,所以只是网上查查资料了解了解:

  • 分库:将一个数据库拆分成多个数据库,主要是用于当单台数据库存储数据过多,或者连接数量需要拓展以提高吞吐量的时候,就需要分库操作。
  • 分表:将一张表拆分成多个表,主要用于降低单表数据,以防查询数据过多导致的慢查询。

  补充一个分区:就是将一张表的数据分散到多个硬盘,或者说服务器中,主要是用于数据管理粒度的降低,也就是讲数据管理的单位减小,方便数据管理和迁移。

mysql中的锁有哪些?

  下面介绍常见的几种锁:

  • 全局锁:也就是将整个数据库锁起来,一般用于对整个数据库数据的处理,如数据备份,数据迁移。
  • 表锁:顾名思义,就是将整张表锁起来,用的少。
  • 元数据锁:在修改表结构的时候,会给表上元数据锁,这时候就无法进行表的读写操作。
  • record锁:用于锁住表中的一条记录。
  • gap锁:用于锁住表中的一段范围记录,这个范围内是没有数据的,并且范围是开区间的,被用在可重复读隔离级别下解决幻读的现象。
  • next-key锁:record锁+gap锁结合,也就是这个范围可以包含表中数据了。

悲观锁和乐观锁是什么?他们是真实存在的吗?

  这里应该是上面问题的延续,所以只讨论mysql中的情况:
  悲观锁指的是对于任何情况都是悲观的,认为数据随时产生冲突的可能,具有独占性,不管是读操作还是写操作,都会上锁,在mysql中写操作都会上锁,读操作则需要使用 SELECT…FOR UPDATE来进行上锁,已到达实现悲观锁的效果。
  乐观锁则是对数据持乐观看法,他认为只有在写操作的时候才会造成数据冲突,所以只对写操作上锁,读操作不上锁,在mysql中默认就是这种模式,或者我们可以使用版本号机制实现。


JSP做过吗?

  做过,但是仅仅是做过。


Java分层?没听过这个,后面聊到了MVC,应该是问的这个的,问了MVC是什么?

  这里就直接说说啥事MVC吧,不清楚贴主说的分层是啥。
  MVC是一种软件架构,并不是Java特有的,MVC每个字母分别代表了模型(MODEL)、视图(VIEW)和控制器(CONTROLLER),下面分别说说各自是什么:

  • 模型:模型负责表示应用程序的数据和业务逻辑,也就是我们常说的实体类,用于对数据的抽象和数据的存储等。
  • 视图:视图负责展示模型数据,也就是我们看到的网页,软件界面等。
  • 控制器:控制器负责处理用户的输入事件,并相应地更新模型和视图,简单来说就是模型和视图的中介。

为什么这样分层有什么好处?

  直接说优点:

  • 代码重用:通过将业务逻辑与用户界面分开,可以更容易地重用模型和视图部分,使其在不同的应用程序中复用。
  • 可扩展性:由于MVC模式强调了松耦合,因此很容易在不影响其他部分的情况下扩展应用程序的功能。
  • 便于维护:分层以后,各层之间的代码区分开,出现问题可以更快的定位问题所在。




剩下的就是结合简历的题目了,这里也答不了了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值