Java面试全攻略:从基础到实战,互联网大厂技术栈深度解析
面试场景模拟
第一轮:Java基础与JVM
-
面试官:请解释Java中的
final
关键字有哪些用法? 光头强:final
可以修饰类、方法和变量。修饰类时类不能被继承,修饰方法时方法不能被重写,修饰变量时变量值不能改变。 面试官:很好!那final
修饰的变量是线程安全的吗? 光头强:呃……这个……应该是吧? -
面试官:Java中的垃圾回收机制有哪些算法? 光头强:标记-清除、复制、标记-整理、分代收集。 面试官:不错!能详细说说分代收集的原理吗? 光头强:这个……大概是把对象分年轻代和老年代?
第二轮:并发编程
-
面试官:
synchronized
和ReentrantLock
有什么区别? 光头强:synchronized
是关键字,ReentrantLock
是类。后者更灵活,可以设置超时和公平锁。 面试官:很好!那ReentrantLock
的公平锁和非公平锁有什么区别? 光头强:公平锁是按顺序获取锁,非公平锁是……呃……随便抢? -
面试官:什么是线程池的核心参数? 光头强:核心线程数、最大线程数、队列容量、拒绝策略。 面试官:很棒!那
ThreadPoolExecutor
的拒绝策略有哪些? 光头强:这个……好像是抛异常、丢弃任务、调用者运行?
第三轮:Spring框架
-
面试官:Spring Bean的生命周期有哪些阶段? 光头强:实例化、属性赋值、初始化、销毁。 面试官:很好!能说说
@PostConstruct
和@PreDestroy
的作用吗? 光头强:一个是初始化后调用,一个是销毁前调用。 -
面试官:Spring AOP的实现原理是什么? 光头强:动态代理! 面试官:具体是JDK动态代理还是CGLIB? 光头强:呃……看情况?
第四轮:数据库与缓存
-
面试官:MySQL的索引有哪些类型? 光头强:B+树、哈希、全文索引。 面试官:很好!那B+树索引为什么适合范围查询? 光头强:因为……叶子节点是链表?
-
面试官:Redis的持久化机制有哪些? 光头强:RDB和AOF。 面试官:很棒!那AOF的重写机制是什么? 光头强:这个……好像是压缩日志?
第五轮:微服务与实战
-
面试官:Spring Cloud的服务注册与发现是如何实现的? 光头强:用Eureka或者Consul。 面试官:很好!那Eureka的自我保护机制是什么? 光头强:呃……心跳检测失败时不踢出服务?
-
面试官:如何设计一个高并发的秒杀系统? 光头强:用Redis缓存库存,异步扣减,限流。 面试官:很棒!那如何防止超卖? 光头强:这个……用分布式锁?
深度答案解析
1. final
关键字的线程安全性
final
修饰的变量在初始化后不可变,因此是线程安全的。但如果是引用类型,对象内部的属性仍然可能被修改。
2. 分代收集算法
分代收集基于对象存活时间将堆分为年轻代和老年代。年轻代使用复制算法,老年代使用标记-清除或标记-整理算法。
3. ReentrantLock
的公平锁
公平锁严格按照线程请求顺序分配锁,避免饥饿;非公平锁允许插队,提高吞吐量但可能导致饥饿。
4. Spring AOP的动态代理
Spring默认对接口使用JDK动态代理,对类使用CGLIB。可通过proxyTargetClass=true
强制使用CGLIB。
5. Redis AOF重写
AOF重写通过生成新的AOF文件,移除冗余命令,压缩日志体积。
6. 防止超卖的方案
- 乐观锁:通过版本号控制。
- 分布式锁:如Redis的
SETNX
。 - 预扣减:先扣减缓存,再异步落库。
// 乐观锁示例
@Transactional
public boolean reduceStock(Long productId, int quantity) {
Product product = productDao.selectById(productId);
if (product.getStock() >= quantity) {
product.setStock(product.getStock() - quantity);
product.setVersion(product.getVersion() + 1);
return productDao.updateById(product) > 0;
}
return false;
}