记录自己第n次面试(n>3)
1. Spring Boot 可执行 JAR 的内存分配
答:
“在 Spring Boot 可执行 JAR 中,JVM 的内存通常分为两大块:堆(Heap)和栈(Stack)。
堆内存:存放对象实例和数组,通过
-Xms
(初始)和-Xmx
(最大)控制。比如java -Xms512m -Xmx1024m -jar app.jar
,表示启动时给 512 MB 堆,最大可以到 1 024 MB。栈内存:每个线程有独立的栈帧,用来保存方法调用的局部变量、操作数等,通过
-Xss
控制,比如-Xss512k
把每个线程栈定为 512 KB。
这样,当我们启动微服务时,就能根据业务并发和对象创建量,合理调整堆和栈的大小,避免 OOM 或栈溢出。”
你可以加上一句“在生产环境中,一般会压测不同设置对 GC 和吞吐的影响,再确定最终参数。”
2. 什么是线程池?如何创建?
答:
“线程池就是一组可复用的、预先创建好的工作线程,通过一个任务队列和若干线程来执行异步任务。好处是:
减少开销:避免频繁创建和销毁线程带来的性能损失。
控制并发:限制最大并发线程数,防止资源耗尽。
统一管理:可以监控、调整、优雅关闭。
在 Java 中,最简单的方法是使用
Executors
工厂:ExecutorService pool = Executors.newFixedThreadPool(10);
但生产环境更推荐手动 new
ThreadPoolExecutor
,可精细配置核心线程数、最大线程数、队列长度、超时、线程工厂和拒绝策略,比如:ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 20, 60, TimeUnit.SECONDS,new LinkedBlockingQueue<>(200),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy() );
这样可以根据业务峰值做更精准的调优。”
3. 线程不安全集合 vs. 线程安全集合
答:
“Java 的集合分为线程不安全和线程安全两类:
不安全:
ArrayList
、HashMap
、LinkedList
。它们在多线程并发写入时,没有任何同步,容易丢失更新、出现数据结构破坏(如HashMap
扩容时形成环链导致死循环)。安全:
Vector
、Hashtable
、Collections.synchronizedXXX(...)
、ConcurrentHashMap
。其中最推荐的是
ConcurrentHashMap
,它采用分段锁(Java 8 又优化为 bin-level CAS+锁),在高并发场景下性能和可伸缩性都很好。”
4. “61 人能选,153 人时不能选”的选课问题
答:
“这个问题常见于 ‘超限’ 校验和数据类型范围同时影响的场景。
并发校验竞态:如果用 ‘先查数再插入’ 的模式,多个用户同时查到人数为 60,都通过了校验,就可能继续插入到 61。
数据库字段溢出:假设人数字段用了
TINYINT
(-128~127),61 还在范围内,所以能插入;153 超过 127,就会报错或被截断,导致选课失败。最佳实践:
在数据库层加锁或用乐观锁(version),保证加一操作原子;
将计数字段改为
INT
;在插入前后都做双重校验,并捕获数据库异常给出明确提示。”