互联网大厂Java面试大揭秘:核心知识与实战问答
面试官:第一轮面试开始,首先问你,说说Java中的多线程在实际业务场景中有哪些应用?
王铁牛:多线程嘛,在电商抢购的时候可以用,多个线程同时去抢商品,提高抢购效率。
面试官:回答得不错。那再问你,线程池的核心参数有哪些,分别有什么作用?
王铁牛:有corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。corePoolSize是核心线程数,maximumPoolSize是最大线程数,keepAliveTime是线程存活时间,unit是时间单位,workQueue是任务队列,threadFactory是线程工厂,handler是拒绝策略。
面试官:很好,看来你对基础还是有一定了解的。最后一个问题,在高并发场景下,如何合理配置线程池参数?
王铁牛:这个嘛,我觉得要根据业务场景来,比如任务量大小、任务执行时间等等。
面试官:好,第一轮面试结束。
面试官:第二轮面试,说一下JVM的内存模型,以及各个区域的作用。
王铁牛:JVM内存模型包括堆、栈、方法区等。堆是存放对象实例的地方,栈是存放局部变量和方法调用的地方,方法区存放类信息、常量等。
面试官:那对象在堆中是如何分配内存的?
王铁牛:这个不太清楚,大概就是new对象的时候就分配了吧。
面试官:JVM的垃圾回收算法有哪些?
王铁牛:有标记清除、标记整理、复制算法等。
面试官:第二轮面试完毕。
面试官:第三轮面试,讲讲Spring框架中依赖注入的几种方式。
王铁牛:有构造器注入、setter注入、接口注入。
面试官:Spring Boot的自动配置原理是什么?
王铁牛:这个……不太明白,感觉就是自动配置一些东西吧。
面试官:最后问你,MyBatis的动态SQL有哪些应用场景?
王铁牛:不太清楚,没用过多少。
面试官:好,面试结束了。回家等通知吧。
答案:
- 多线程在电商抢购中的应用:在电商抢购场景下,多个线程同时尝试获取商品库存并下单,这样可以极大提高抢购的效率,减少用户等待时间。每个线程相当于一个抢购者,它们并发执行抢购操作。
- 线程池核心参数:
- corePoolSize:核心线程数,当提交的任务数小于corePoolSize时,线程池会创建新线程来执行任务。
- maximumPoolSize:最大线程数,当任务数超过corePoolSize且workQueue已满时,会创建新线程直到线程数达到maximumPoolSize。
- keepAliveTime:线程存活时间,当线程数大于corePoolSize时,多余的线程在空闲时间超过keepAliveTime后会被销毁。
- unit:时间单位,用于指定keepAliveTime的时间单位。
- workQueue:任务队列,用于存放提交的任务,当线程数达到corePoolSize时,新任务会被放入workQueue。
- threadFactory:线程工厂,用于创建线程,可自定义线程的一些属性。
- handler:拒绝策略,当线程数达到maximumPoolSize且workQueue已满时,会调用handler来处理新提交的任务。
- 高并发场景下合理配置线程池参数:要根据业务场景中任务的特性来配置。如果任务执行时间短,可适当增大corePoolSize;如果任务执行时间长,应合理设置maximumPoolSize,避免线程过多占用资源。同时要结合任务队列的大小,如任务量多且执行时间短,可适当增大队列容量,减少线程创建频率。
- JVM内存模型及各区域作用:
- 堆:是存放对象实例的地方,是JVM内存中最大的一块区域,所有对象都在堆中创建。
- 栈:主要存放局部变量和方法调用的上下文。每个线程都有自己独立的栈空间。
- 方法区:用于存放类信息、常量、静态变量等。
- 对象在堆中分配内存过程:当执行new操作时,JVM首先会检查堆是否有足够的连续空间来存放对象。如果有,就为对象分配内存,并将对象的成员变量初始化默认值。然后会调用对象的构造函数进行初始化。如果堆中没有足够空间,会触发垃圾回收,回收后若有空间则继续分配。
- JVM垃圾回收算法:
- 标记清除算法:先标记出所有需要回收的对象,然后统一回收这些对象所占用的空间。但这种算法会产生大量不连续的内存碎片。
- 标记整理算法:先标记出需要回收的对象,然后将存活对象向一端移动,最后清理端边界以外的内存。
- 复制算法:将内存空间分为两块,每次只使用其中一块。当这块空间满了,就将存活对象复制到另一块空间,然后清理原来的空间。适用于对象存活率低的场景。
- Spring框架中依赖注入的几种方式:
- 构造器注入:通过构造函数来注入依赖,这种方式注入的依赖一旦注入就不可变。
- setter注入:通过setter方法来注入依赖,这种方式可以在对象创建后再注入依赖,更加灵活。
- 接口注入:实现一个接口,在接口中定义注入方法,然后在类中实现该接口来完成依赖注入,使用较少。
- Spring Boot自动配置原理:Spring Boot通过大量的@Configuration和@Bean注解的配置类来实现自动配置。它会根据项目中引入的依赖,自动配置相关的组件和属性。比如引入了Spring Data JPA依赖,就会自动配置JPA相关的数据源、事务管理器等。它通过条件注解来判断是否需要进行自动配置,只有当满足特定条件时才会生效。
- MyBatis动态SQL应用场景:在查询场景中,根据不同条件动态生成查询语句。比如根据用户传入的参数动态决定查询条件是按用户名还是按用户ID。在更新场景中,根据业务规则动态更新部分字段。例如订单状态改变时,可能只更新订单状态字段,而其他字段不变,就可以通过动态SQL实现精准更新。