Java八股文面试50问速通:从JVM到Spring Boot全覆盖
涵盖JVM、并发、Spring、MySQL、Redis、消息队列、分布式7大模块50道Java高频面试题,每题含简要答案方向,助你速通技术面。
Java八股文面试50问速通:从JVM到Spring Boot全覆盖
背景介绍
说实话,我第一次听到"八股文"这个词的时候还挺反感的——什么年代了还背题?但面了七八家大厂之后我彻底悟了:八股文不是让你死记硬背,而是帮你建立知识体系的骨架。我整理了这50道最高频的Java面试题,每一道都是我在真实面试中被问到的,覆盖JVM、并发、Spring、MySQL、Redis、消息队列、分布式七大模块。不管你是校招还是社招,吃透这些,面试至少能过技术面。
一、JVM(8题)
1. JVM内存模型是怎样的?
堆(新生代+老年代)、方法区/元空间、虚拟机栈、本地方法栈、程序计数器。堆是线程共享的,栈和计数器是线程私有的。面试官最爱追问:为什么要把堆分新生代和老年代?因为大部分对象朝生夕死,新生代用复制算法效率高。
2. 说一下GC算法有哪些?
标记-清除(有碎片)、标记-整理(无碎片但慢)、复制算法(新生代用,快但费空间)、分代收集(综合方案)。追问必问CMS和G1:CMS用标记-清除,有浮动垃圾和碎片问题;G1用分区+混合回收,可预测停顿时间。
3. 类加载机制和双亲委派模型?
加载→验证→准备→解析→初始化。双亲委派:先让父加载器加载,父加载器搞不定才自己来。好处是避免重复加载和安全问题。打破双亲委派的例子:SPI机制(线程上下文类加载器)、Tomcat(每个webapp独立类加载器)。
4. 什么情况下会发生OOM?怎么排查?
堆溢出(对象太多)、元空间溢出(动态生成类太多)、栈溢出(递归太深)。排查:jmap看堆内存、jstack看线程栈、MAT分析dump文件。我面试时被追问过线上OOM怎么处理——先加-XX:+HeapDumpOnOutOfMemoryError参数,出了问题有dump可分析。
5. JVM调优参数有哪些?
-Xms/-Xmx设堆大小、-Xmn设新生代大小、-XX:SurvivorRatio设Eden和Survivor比例、-XX:MetaspaceSize设元空间大小、-XX:+UseG1GC选垃圾收集器。实际调优经验:先把-Xms和-Xmx设一样避免动态扩容,G1的MaxGCPauseMillis设200ms。
6. 强引用、软引用、弱引用、虚引用的区别?
强引用不回收、软引用内存不足时回收(适合缓存)、弱引用GC就回收(ThreadLocal的key)、虚引用仅用于跟踪GC活动。这个题看着简单,但面试官会追问ThreadLocal内存泄漏——key是弱引用会被回收,但value是强引用不会,所以用完要remove。
7. JVM中对象的创建过程?
类加载检查→分配内存(指针碰撞或空闲列表)→初始化零值→设置对象头→执行init方法。并发安全用CAS或TLAB。追问:对象在内存中的布局?对象头(Mark Word+类型指针)、实例数据、对齐填充。
8. 垃圾收集器怎么选择?
单CPU小内存用Serial、多CPU追求吞吐用Parallel Scavenge+Parallel Old、低延迟用CMS或G1、大堆+可预测延迟用ZGC。实际经验:JDK8用CMS或G1,JDK11+直接G1,JDK15+可以考虑ZGC。
二、并发(10题)
9. synchronized和ReentrantLock的区别?
synchronized是关键字,ReentrantLock是API;synchronized自动释放锁,ReentrantLock要手动unlock;ReentrantLock支持公平锁、可中断、多条件变量。我面试时被问:什么场景用ReentrantLock更好?答:需要公平排队、需要tryLock避免死锁、需要多个Condition时。
10. volatile关键字的作用?
保证可见性(刷回主内存)和禁止指令重排序,不保证原子性。底层用内存屏障实现。经典场景:DCL单例模式中instance要加volatile防止初始化一半的对象被其他线程看到。
11. 线程池的核心参数和执行流程?
corePoolSize、maximumPoolSize、keepAliveTime、workQueue、threadFactory、rejectedExecutionHandler。执行流程:先核心线程→再队列→再非核心线程→再拒绝策略。四大拒绝策略:AbortPolicy(抛异常)、CallerRunsPolicy(调用者执行)、DiscardPolicy(丢弃)、DiscardOldestPolicy(丢弃最老)。面试必问:线程池怎么设置参数?CPU密集型设N+1,IO密集型设2N或根据公式计算。
12. AQS原理?
核心是volatile int state和一个CLH双向等待队列。独占模式(ReentrantLock)state为0可获取,为1则入队等待;共享模式(Semaphore)state表示剩余许可数。模板方法模式:子类实现tryAcquire/tryRelease。我面试时被让手写一个简单的AQS——其实就是继承AQS重写tryAcquire就行。
13. ThreadLocal原理和内存泄漏问题?
每个Thread对象有个ThreadLocalMap,key是ThreadLocal弱引用,value是强引用。内存泄漏原因:ThreadLocal被GC后key变null,但value还在。解决方案:用完调用remove()。追问:线程池中用ThreadLocal要注意什么?线程复用导致数据串,一定要在finally里remove。
14. CAS是什么?有什么问题?
Compare And Swap,比较并交换,乐观锁的实现。问题:ABA问题(用AtomicStampedReference解决)、自旋开销(竞争激烈时CPU空转)、只能保证一个共享变量的原子操作(用AtomicReference包装多个变量)。
15. 说说Java中的锁分类?
悲观锁/乐观锁、公平锁/非公平锁、独占锁/共享锁、可重入锁/不可重入锁、自旋锁/阻塞锁。synchronized是悲观、非公平、独占、可重入锁。ReentrantLock默认非公平,可设公平。
16. CountDownLatch和CyclicBarrier的区别?
CountDownLatch是一次性的,等N个线程完成;CyclicBarrier可复用,N个线程互相等待到齐后继续。场景:CountDownLatch适合主线程等待子线程完成,CyclicBarrier适合多线程分段计算后汇总。
17. Fork/Join框架?
分治+工作窃取算法。大任务拆成小任务fork出去,结果join合并。工作窃取:空闲线程从别的线程队列尾部偷任务执行。适合CPU密集型的递归计算任务。
18. happen-before原则?
八大规则:程序顺序、volatile、锁、传递性、线程启动、线程终止、线程中断、对象终结。不是"时间上先发生",而是"前一个操作的结果对后一个操作可见"。
三、Spring(8题)
19. Spring IOC的理解?
控制反转,把对象的创建和依赖管理交给容器。实现方式:依赖注入(DI),包括构造器注入、Setter注入、字段注入(@Autowired)。Bean生命周期:实例化→属性赋值→初始化→使用→销毁。面试官爱问:BeanPostProcessor和BeanFactoryPostProcessor的区别?前者处理Bean实例,后者处理BeanDefinition。
20. Spring AOP的实现原理?
JDK动态代理(接口)和CGLIB(类)。Spring默认有接口用JDK代理,没接口用CGLIB。SpringBoot2.x默认全部CGLIB。通知类型:Before、After、AfterReturning、AfterThrowing、Around。我面试时被问:AOP失效场景?内部方法调用(没走代理)、private方法、static方法。
21. Spring事务传播机制?
REQUIRED(默认,有则加入无则新建)、REQUIRES_NEW(总是新建,挂起当前)、NESTED(嵌套事务)、SUPPORTS、NOT_SUPPORTED、MANDATORY、NEVER。最常考REQUIRED vs REQUIRES_NEW:前者内外同一事务一起回滚,后者内层独立回滚不影响外层。
22. Spring如何解决循环依赖?
三级缓存:singletonObjects(完整Bean)、earlySingletonObjects(早期引用)、singletonFactories(Bean工厂)。流程:A创建→发现依赖B→B创建→发现依赖A→从三级缓存拿A的早期引用→B完成→A完成。注意:构造器注入和原型模式无法解决。面试追问:为什么需要三级缓存而不是两级?为了处理AOP代理,保证早期引用和最终引用一致。
23. @Autowired和@Resource的区别?
@Autowired按类型注入(Spring),@Resource按名称注入(JSR-250)。@Autowired配合@Qualifier按名称,@Resource的name属性指定名称。面试官会问:多个同类型Bean怎么办?@Primary或@Qualifier。
24. SpringBoot自动装配原理?
@SpringBootApplication包含@EnableAutoConfiguration→通过SpringFactoriesLoader加载META-INF/spring.factories中的配置类→根据@Conditional条件过滤→装配Bean。SpringBoot2.7+改用META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。
25. Spring中设计模式的应用?
工厂(BeanFactory)、单例(Bean默认scope)、代理(AOP)、模板方法(JdbcTemplate)、观察者(事件机制)、适配器(HandlerAdapter)、策略(ResourceLoader)。这个题能展示你对Spring的理解深度。
26. SpringMVC的请求处理流程?
请求→DispatcherServlet→HandlerMapping找Handler→HandlerAdapter执行→Controller处理→返回ModelAndView→ViewResolver解析视图→响应。面试追问:拦截器和过滤器的区别?拦截器是Spring的,过滤器是Servlet的;拦截器能拿到Handler信息,过滤器不能。
四、MySQL(8题)
27. MySQL索引的数据结构?为什么用B+树?
InnoDB用B+树。原因:1)树矮(3-4层存千万数据),IO少;2)叶子节点链表连接,范围查询快;3)非叶子只存key,一个页能存更多key。追问:聚簇索引vs非聚簇索引?聚簇索引叶子存整行数据(主键索引),非聚簇索引叶子存主键值(二级索引),查非索引列要回表。
28. 事务的隔离级别?
读未提交(脏读)、读已提交(不可重复读)、可重复读(幻读,MySQL默认)、串行化。InnoDB在RR级别通过MVCC+间隙锁解决大部分幻读。MVCC:每行有隐藏列trx_id和roll_pointer,读操作通过ReadView判断可见性。
29. MySQL锁机制?
表锁(开销小并发低)、行锁(开销大并发高)、间隙锁(锁索引间隙防幻读)、临键锁(行锁+间隙锁)。InnoDB行锁是加在索引上的,不走索引则退化为表锁!面试必问:怎么查看锁情况?show engine innodb status或查information_schema.INNODB_LOCKS。
30. 慢查询怎么优化?
1)EXPLAIN看执行计划;2)检查是否走索引;3)避免select *;4)避免索引失效(函数、隐式转换、%开头like、or);5)合理建索引(联合索引最左前缀);6)分页优化(延迟关联);7)数据量大考虑分库分表。
31. 联合索引的最左前缀原则?
索引(a,b,c)能匹配a、a,b、a,b,c,不能匹配b、c、b,c。但MySQL优化器会调整顺序,where b=1 and a=2也能用索引。范围查询后的列不走索引:where a>1 and b=2,只有a走索引。
32. MySQL主从复制原理?
主库写binlog→从库IO线程拉取binlog写relay log→从库SQL线程执行relay log。异步复制可能丢数据,半同步复制至少一个从库确认收到binlog。追问:主从延迟怎么处理?读自己的主库、强制走主库、判断seconds_behind_master。
33. 分库分表方案?
垂直拆分(按业务拆库)、水平拆分(按规则分表)。分片键选择:查询频率高的字段。中间件:ShardingSphere、MyCat。分库分表后的问题:分布式事务、跨库join、全局ID(雪花算法)、数据迁移。
34. EXPLAIN中type字段的含义?
从好到差:system>const>eq_ref>ref>range>index>ALL。至少要达到range级别,避免ALL(全表扫描)。Extra中Using index表示覆盖索引(好),Using filesort和Using temporary需要优化。
五、Redis(6题)
35. Redis为什么快?
1)纯内存操作;2)单线程避免上下文切换和锁竞争;3)IO多路复用(epoll);4)高效的数据结构。追问:Redis6.0为什么引入多线程?为了提升网络IO性能,命令执行还是单线程。
36. Redis的数据结构?
5种基本:String、List、Hash、Set、ZSet。底层编码:String用SDS、List用quicklist、Hash用ziplist/hashtable、Set用intset/hashtable、ZSet用ziplist/skiplist+hashtable。面试官爱问:skiplist为什么不用红黑树?实现简单、范围查询方便、插入只需调整相邻节点。
37. Redis持久化方式?
RDB(快照,恢复快但可能丢数据)和AOF(追加日志,数据安全但文件大)。混合持久化:RDB做全量+AOF做增量。AOF三种刷盘策略:always(每条)、everysec(每秒)、no(系统决定)。推荐everysec。
38. Redis缓存穿透、击穿、雪崩?
穿透(查不存在的数据):布隆过滤器、缓存空值。击穿(热点key过期):互斥锁、热点key永不过期。雪崩(大量key同时过期):随机过期时间、多级缓存、限流降级。这三个问题几乎必考,要能完整说出方案。
39. Redis集群方案?
主从复制(读写分离)、哨兵(自动故障转移)、Cluster(分片存储16384个slot)。Cluster方案:客户端key做CRC16%16384算slot,每个节点负责一部分slot。面试追问:集群能保证强一致性吗?不能,异步复制可能丢数据。
40. Redis分布式锁怎么实现?
SET key value NX EX 30(原子操作)。value用UUID防止误删别人的锁。释放锁用Lua脚本保证原子性:先判断value是否一致再删除。Redisson框架做了看门狗自动续期。追问:RedLock算法?多个Redis实例,过半加锁成功才算成功,但有争议。
六、消息队列(5题)
41. 为什么用消息队列?
解耦、异步、削峰。缺点:系统复杂度增加(重复消费、消息丢失、顺序问题)、可用性降低。面试官会问:怎么保证消息不丢?生产者确认+MQ持久化+消费者手动ACK。
42. Kafka架构和核心概念?
Producer→Broker(Topic→Partition→Replica)→Consumer Group。Partition是并行度单位,同一Consumer Group内一个Partition只能被一个Consumer消费。ISR机制:Leader维护一个同步副本集合,只有ISR中的副本才能成为新Leader。
43. Kafka怎么保证消息顺序?
同一Partition内消息有序。要保证全局有序只能一个Partition(不推荐)。实际方案:相同业务key发到同一Partition。追问:Consumer rebalance导致重复消费怎么办?幂等处理。
44. RocketMQ和Kafka的区别?
RocketMQ支持事务消息、延迟消息、消息回溯;Kafka吞吐更高、生态更好。RocketMQ用NameServer(无状态),Kafka用ZooKeeper。选型:日志采集用Kafka,业务消息用RocketMQ。
45. 消息积压怎么处理?
紧急:增加Consumer数量(注意不能超过Partition数)、临时扩容Consumer。长期:排查消费慢的原因、优化消费逻辑、增加Partition。我遇到过一次线上积压500万条,最后是消费端DB慢查询导致的。
七、分布式(5题)
46. CAP定理和BASE理论?
CAP:一致性、可用性、分区容错性三者不可兼得,网络分区必然存在,所以CP或AP二选一。BASE:基本可用、软状态、最终一致性,是CAP中AP的延伸。ZooKeeper是CP(选举期间不可用),Eureka是AP(不去强一致)。
47. 分布式锁的实现方案?
Redis(SET NX EX)、ZooKeeper(临时顺序节点)、MySQL(唯一索引或for update)。对比:Redis性能高但可靠性一般、ZK可靠但性能低、MySQL最简单但不适合高并发。实际推荐Redis+Redisson。
48. 分布式事务方案?
2PC(强一致但阻塞)、TCC(Try-Confirm-Cancel,业务侵入大)、SAGA(长事务拆分+补偿)、本地消息表+MQ(最终一致)、Seata框架。面试常问:你们项目用的什么方案?大多数互联网项目用最终一致性就够了。
49. 分布式ID生成方案?
UUID(无序太长)、数据库自增(性能瓶颈)、号段模式(一次取一批)、雪花算法(时间戳+机器ID+序列号,趋势递增)、Redis自增。雪花算法问题:时钟回拨(保留几位做回拨检测)。
50. 服务熔断和降级的区别?
熔断是调用方保护自己(连续失败后直接断开,类似保险丝),降级是主动放弃非核心功能保核心(返回默认值或兜底数据)。Sentinel和Hystrix都支持。熔断三状态:关闭→打开→半打开(试探恢复)。
真题汇总
以上50题就是我在字节、阿里、美团、快手等大厂面试中真实遇到的高频题。其中最常被问到的Top 10:JVM内存模型、GC算法、synchronized和ReentrantLock、线程池参数、AQS、Spring循环依赖、MySQL索引、事务隔离级别、Redis缓存三连、分布式锁。建议按出现频率从高到低准备。
心得建议
1. 不要死记硬背,理解原理才能应对追问。面试官一个"为什么"就能筛掉背答案的人。
2. 建立知识图谱,比如JVM→GC→调优是一条线,synchronized→锁升级→AQS是一条线,串联起来记忆更牢固。
3. 结合项目经验,每个知识点准备一个实际场景。比如"我在项目中遇到OOM,通过jmap发现是ThreadLocal没remove导致的内存泄漏"。
4. 适度刷源码,不用全看,但AQS的acquire/release、Spring的getBean流程、HashMap的put流程建议跟一遍。
5. 模拟面试,找人互相问,能说出来和能写出来是两回事,能流畅表达又是另一回事。
FAQ
Q:八股文要背到什么程度?
A:至少能用自己的话完整说出来,关键术语不能错,能应对一层追问。比如你说完JVM内存模型,面试官问"方法区和元空间的区别",你得接得住。
Q:只准备八股文够吗?
A:不够。八股文是基础,还需要项目经验、算法、系统设计。但八股文不过关,其他再好也过不了技术面。
Q:社招和校招八股文侧重点一样吗?
A:校招偏基础原理(JVM、并发、集合),社招偏实战经验(调优、排障、架构选型)。社招一定要结合项目讲,不能纯背。
Q:多久能准备完这50题?
A:有Java基础的,集中准备2-3周。建议每天5-8题,每题理解+写笔记+能口述。不要贪多,吃透比刷量重要。