《互联网大厂 Java 面试:从基础到进阶的核心知识大考察》

45 阅读7分钟

第一轮面试 面试官:首先问几个基础问题。讲讲Java中ArrayList和HashMap的区别。 王铁牛:ArrayList是有序的,按顺序存储元素,HashMap是无序的,通过键值对存储。 面试官:不错,回答得很清晰。那HashMap在多线程环境下会有什么问题? 王铁牛:嗯……好像会数据错乱,因为它不是线程安全的。 面试官:回答得可以。再说说Spring框架中IOC是什么? 王铁牛:IOC就是控制反转,把对象创建和管理的控制权交给Spring容器。 面试官:很好,基础掌握得不错。

第二轮面试 面试官:接下来深入一些。Spring Boot自动配置原理是什么? 王铁牛:呃,就是Spring Boot能根据依赖自动配置一些东西,具体咋实现的我不太清楚。 面试官:那MyBatis的一级缓存和二级缓存了解吗?讲讲。 王铁牛:一级缓存好像是在一个SqlSession内有效,二级缓存是多个SqlSession共享,具体细节我有点模糊。 面试官:好,Dubbo的服务注册与发现机制是怎样的? 王铁牛:就是服务提供者把服务注册到注册中心,消费者从注册中心获取服务,大概这样。 面试官:回答得不是很清晰,继续下一轮。

第三轮面试 面试官:JVM的垃圾回收机制讲讲,比如常见的垃圾回收算法有哪些? 王铁牛:有标记 - 清除算法,还有复制算法,其他的我一时想不起来了。 面试官:JUC包下的线程池ThreadPoolExecutor的核心参数有哪些,分别有什么作用? 王铁牛:有核心线程数、最大线程数,还有个队列容量,核心线程数就是一开始创建的线程数,最大线程数就是最多能创建的线程数,队列容量就是存放任务的队列大小。 面试官:RabbitMQ的消息确认机制是怎样的? 王铁牛:好像是生产者发送消息后,RabbitMQ会给个确认,具体咋确认的不太明白。 面试官:最后,xxl - job的调度原理是什么? 王铁牛:这个……我不太了解。

面试官:今天的面试就到这里,你整体基础部分回答得还可以,但深入的技术点理解不够透彻。回去等通知吧,我们会综合评估所有候选人后,再做决定。

问题答案

  1. ArrayList和HashMap的区别
    • 存储结构:ArrayList是基于数组实现的,有序存储元素,可通过索引访问元素;HashMap是基于哈希表实现的,以键值对形式存储,无序。
    • 线程安全性:ArrayList和HashMap都不是线程安全的。
    • 应用场景:ArrayList适合需要顺序访问、频繁插入删除元素在尾部的场景;HashMap适合根据键快速查找值的场景。
  2. HashMap在多线程环境下的问题
    • 数据错乱:多线程同时put数据时,可能会导致哈希表结构被破坏,出现数据覆盖、链表成环等问题,最终导致程序出现难以排查的错误。因为HashMap在扩容等操作时不是线程安全的。
  3. Spring框架中IOC(控制反转)
    • 概念:传统应用中,对象创建和依赖关系管理由应用自身负责。IOC则是将这种控制权反转给Spring容器。Spring容器负责创建对象、管理对象的生命周期以及对象之间的依赖关系。
    • 实现方式:通过XML配置文件或注解方式,告诉Spring容器要创建哪些对象,以及对象之间的依赖关系。例如使用@Autowired注解自动注入依赖对象。
  4. Spring Boot自动配置原理
    • 核心机制:Spring Boot通过@EnableAutoConfiguration注解开启自动配置。它会根据classpath下存在的依赖,结合SpringFactoriesLoader机制,从META - INF/spring.factories文件中加载对应的自动配置类。这些自动配置类会根据条件(如@ConditionalOnClass、@ConditionalOnProperty等注解)判断是否生效,从而自动配置相关的Bean到Spring容器中。
  5. MyBatis的一级缓存和二级缓存
    • 一级缓存:作用域是SqlSession,在同一个SqlSession内,执行相同的SQL查询时,MyBatis会先从一级缓存中查找数据,若存在则直接返回,不再执行SQL查询。当SqlSession执行commit、rollback等操作修改数据时,一级缓存会被清空。
    • 二级缓存:作用域是namespace,多个SqlSession可以共享二级缓存。二级缓存需要手动开启,并且缓存的对象需要实现Serializable接口。当一个SqlSession修改了数据,会通知其他SqlSession清空二级缓存。
  6. Dubbo的服务注册与发现机制
    • 服务注册:服务提供者启动时,会将自己提供的服务信息(如接口、方法等)注册到注册中心(如Zookeeper)。注册中心维护着服务提供者的地址列表等信息。
    • 服务发现:服务消费者启动时,会从注册中心订阅自己需要的服务。注册中心会将服务提供者的地址列表返回给消费者。当服务提供者地址发生变化时,注册中心会通知消费者。
  7. JVM的垃圾回收机制及常见垃圾回收算法
    • 标记 - 清除算法:分为标记和清除两个阶段。标记阶段标记出所有需要回收的对象,清除阶段回收被标记的对象所占用的空间。缺点是会产生大量不连续的内存碎片。
    • 复制算法:将内存分为大小相等的两块,每次只使用其中一块。当这块内存用完,将存活对象复制到另一块,然后把使用过的内存一次性清理掉。优点是不会产生内存碎片,缺点是内存利用率低。
  8. ThreadPoolExecutor的核心参数
    • corePoolSize(核心线程数):线程池中会一直存活的线程数,即使这些线程处于空闲状态,也不会被销毁,除非设置了allowCoreThreadTimeOut为true。
    • maximumPoolSize(最大线程数):线程池中允许的最大线程数。当任务队列满了且活动线程数达到核心线程数时,新任务会创建新线程,直到线程数达到最大线程数。
    • keepAliveTime(线程存活时间):当线程数大于核心线程数时,多余的空闲线程存活的最长时间,超过这个时间就会被销毁。
    • unit(存活时间单位):keepAliveTime的时间单位,如TimeUnit.SECONDS等。
    • workQueue(任务队列):用于存放等待执行的任务。常见的队列类型有ArrayBlockingQueue、LinkedBlockingQueue等。
  9. RabbitMQ的消息确认机制
    • 生产者确认(publisher confirm):生产者发送消息后,RabbitMQ会给生产者发送确认消息,告知消息是否成功到达服务器。可以通过设置channel.confirmSelect()开启确认模式,生产者通过监听ConfirmListener来处理确认结果。
    • 消费者确认(consumer ack):消费者接收消息后,需要向RabbitMQ发送确认消息,告知消息已被正确处理。如果消费者没有发送确认,RabbitMQ会认为消息没有被成功处理,可能会重新发送给其他消费者。
  10. xxl - job的调度原理
  • 调度中心:负责管理调度任务,包括任务的新增、修改、删除等。调度中心会按照设定的调度规则(如cron表达式)触发任务调度。
  • 执行器:部署在业务系统中,负责接收调度中心的调度请求并执行具体任务。执行器启动时会向调度中心注册自己,调度中心根据执行器的注册信息将任务分配给合适的执行器。调度中心和执行器之间通过HTTP协议进行通信。