作者介绍
🎓 浙江大学软件工程硕士生
💻 淘天后端研发工程师
😇 秋招斩获阿里、字节、快手、京东、美团等多个大厂研发ssp/sp
💡 持续分享秋招经验分享、高频八股问题、最新大厂面经、硬核技术干货……
👏 全网同号,欢迎关注
1、【实习经历】在实习过程中是否遇到过技术难题?如果有,是如何分析和解决的?
- 技术难题
在高并发场景下,系统接口响应时间变长,数据库查询效率低下。 分析与解决过程
- 定位问题:通过日志分析和性能监控工具(如 Arthas 或 JProfiler)发现数据库慢查询是主要瓶颈。
- 数据库优化:对慢查询进行索引优化,并引入 Redis 缓存热点数据,减少数据库直接访问。
- 线程池调优:调整线程池的核心线程数和最大线程数,避免线程过多导致上下文切换开销过大。
- 异步化处理:使用
CompletableFuture
对耗时操作进行异步化处理,提升系统吞吐量。 - 结果:经过优化,系统响应时间显著降低,性能得到明显提升。
2、【并发编程】请谈谈对固定线程池的理解,它的使用场景是什么?有哪些优缺点?使用线程池时可能存在哪些限制?常见的线程池拒绝策略有哪些?
- 固定线程池的理解
固定线程池通过Executors.newFixedThreadPool(int nThreads)
创建,核心线程数和最大线程数相同,且线程数量固定。 - 使用场景
适用于任务量稳定、执行时间较短的任务,例如批量数据处理或定时任务调度。 优点
- 性能优化:线程数量固定,避免频繁创建和销毁线程的开销。
- 资源控制:能够有效控制并发线程数,防止资源耗尽。
缺点
- 内存风险:如果任务队列无界,可能导致内存溢出(OOM)。
- 阻塞问题:不适合执行耗时较长的任务,容易造成线程阻塞。
- 限制
动态扩展不足:线程池大小固定,无法动态扩展,可能不适合任务量波动较大的场景。 常见拒绝策略
- AbortPolicy:直接抛出异常,拒绝新任务。
- CallerRunsPolicy:由调用线程执行被拒绝的任务。
- DiscardPolicy:直接丢弃新任务,不抛异常。
- DiscardOldestPolicy:丢弃队列中最老的任务,尝试重新提交新任务。
3、【项目经验】针对黑马点评项目中的秒杀功能,请详细描述其实现逻辑。
实现逻辑
- 库存预热:将商品库存加载到 Redis 中,利用 Redis 的原子操作(如
decr
)进行库存扣减。 - 限流与排队:通过分布式限流工具(如 Redis 的计数器或令牌桶算法)限制请求流量,避免系统过载。
- 分布式锁:使用 Redisson 分布式锁确保同一商品不会被超卖。
- 订单生成:库存扣减成功后,将订单信息写入消息队列(如 RabbitMQ),由后台消费者异步处理订单入库。
- 幂等性控制:通过唯一标识(如用户 ID + 商品 ID)确保用户不会重复下单。
- 库存预热:将商品库存加载到 Redis 中,利用 Redis 的原子操作(如
优化点
- 缓存热点数据:使用 Redis 缓存热点数据,减少数据库压力。
- 异步处理:异步处理订单生成,提升系统吞吐量。
4、【Redis】Redis 支持哪些数据结构?RDB 和 AOF 备份机制的主要区别是什么?Redis 的过期键删除策略和内存淘汰策略分别有哪些?
支持的数据结构
- 基础结构:String、List、Set、Hash、ZSet(有序集合)。
- 高级结构:Bitmap、HyperLogLog、Geo。
RDB 和 AOF 的区别
- RDB:定期生成快照文件,恢复速度快,但可能丢失最后一次快照后的数据。
- AOF:记录每个写操作命令,数据更完整,但文件体积较大,恢复速度较慢。
过期键删除策略
- 惰性删除:只有在访问键时检查是否过期,过期则删除。
- 定期删除:定时随机检查并删除过期键。
内存淘汰策略
- noeviction:不淘汰数据,返回错误。
- allkeys-lru:淘汰最近最少使用的键。
- volatile-lru:仅淘汰设置了过期时间的键中最近最少使用的键。
- allkeys-random:随机淘汰任意键。
- volatile-random:随机淘汰设置了过期时间的键。
- volatile-ttl:优先淘汰剩余生存时间最短的键。
5、【Redis】Redisson 分布式锁的实现原理是什么?其看门狗机制是如何工作的?
- 分布式锁实现原理
Redisson 使用 Redis 的SETNX
命令实现分布式锁,确保同一时间只有一个客户端能够获取锁。 看门狗机制
- 工作原理:当客户端成功获取锁后,Redisson 会启动一个后台线程(看门狗),定期刷新锁的过期时间,防止因业务逻辑执行时间过长而导致锁提前释放。
- 默认行为:看门狗会每隔 1/3 的锁过期时间自动续期。
6、【并发编程】ThreadLocal 的工作原理是什么?如何避免其引发的内存泄漏问题?在线程池中使用 ThreadLocal 时需要注意哪些事项?
- 工作原理
每个线程都有一个独立的ThreadLocalMap
,用于存储线程本地变量。ThreadLocal
通过set
和get
方法操作线程的ThreadLocalMap
,确保变量在线程间隔离。 避免内存泄漏
- 清理变量:在使用完
ThreadLocal
后,调用remove
方法清除变量。 - 避免强引用:避免将大对象存储在
ThreadLocal
中,减少内存占用。
- 清理变量:在使用完
线程池注意事项
- 显式清理:线程池中的线程是复用的,必须在任务结束时显式调用
remove
方法清理ThreadLocal
。 - 数据污染:如果未清理,
ThreadLocal
变量可能会残留到下一个任务中,导致数据污染。
- 显式清理:线程池中的线程是复用的,必须在任务结束时显式调用
7、【Java集合】HashMap 是否是线程安全的?请描述其 get 方法的执行流程以及底层数据结构。在高并发场景下,HashMap 可能会出现哪些问题?有哪些线程安全的替代方案?它们之间有何区别?
- 线程安全性
HashMap
是非线程安全的,在多线程环境下可能出现死循环或数据丢失。 get 方法流程
- 哈希计算:根据 key 的哈希值计算数组索引。
- 查找节点:遍历链表或红黑树,找到匹配的 key 并返回对应的 value。
- 底层数据结构
JDK 1.8 中,HashMap
底层采用数组 + 链表/红黑树的结构。 高并发问题
- 死循环:多线程同时扩容时可能导致链表成环,造成死循环。
- 数据覆盖:多线程同时写入可能导致数据覆盖或丢失。
线程安全替代方案
- Hashtable:通过
synchronized
实现线程安全,性能较差。 - ConcurrentHashMap:基于分段锁或 CAS 实现高效并发访问。
- Collections.synchronizedMap:对
HashMap
进行包装,性能较低。
- Hashtable:通过
区别
- 性能:
ConcurrentHashMap
性能最优,适合高并发场景。 - 锁粒度:
Hashtable
和synchronizedMap
锁粒度较大,性能较差。
- 性能:
8、【MySQL】MySQL 支持哪些存储引擎?InnoDB 引擎的索引结构是什么?为什么选择 B+ 树作为索引结构?在实际场景中如何合理创建索引?请解释联合索引的作用,并分享实习过程中进行 MySQL 性能优化的经验。
支持的存储引擎
- InnoDB:支持事务,适合高并发场景。
- MyISAM:不支持事务,适合读多写少的场景。
- Memory:数据存储在内存中,适合临时数据处理。
InnoDB 索引结构
- 主键索引:B+ 树,叶子节点存储数据行。
- 辅助索引:B+ 树,叶子节点存储主键值。
选择 B+ 树的原因
- 查询效率:B+ 树的高度较低,查询效率高。
- 范围查询:所有数据都在叶子节点,范围查询效率更高。
合理创建索引的原则
- 查询频率:对查询频率高的字段创建索引。
- 更新频率:避免对更新频繁的字段创建索引。
- 最左前缀原则:使用联合索引时遵循最左前缀原则。
- 联合索引作用
联合索引可以加速多条件查询,减少单字段索引的数量。 性能优化经验
- 添加索引:添加合适的索引,避免全表扫描。
- 分析 SQL:使用 EXPLAIN 分析 SQL 执行计划。
- 减少字段:避免 SELECT *,只查询需要的字段。
9、【JVM】JVM 中堆和栈的主要区别是什么?对象的生命周期是如何管理的?垃圾回收机制的工作原理是什么?对于未被回收的对象,JVM 会如何处理?
堆和栈的区别
- 堆:存放对象实例,所有线程共享,GC 的主要区域。
- 栈:存放局部变量和方法调用,线程私有,随方法调用和返回自动分配和释放。
对象生命周期
- 创建:通过
new
关键字分配内存。 - 使用:对象被引用并参与业务逻辑。
- 回收:当对象不再被引用时,由 GC 回收。
- 创建:通过
垃圾回收机制
- 标记-清除:标记存活对象,清除未标记对象。
- 复制算法:将存活对象复制到另一块内存。
- 标记-整理:标记存活对象并整理内存。
- 未被回收的对象
如果对象仍有引用或处于 GC Roots 可达路径中,JVM 不会回收。
10、【Java基础】volatile 关键字的作用是什么?其底层实现原理是什么?
作用
- 可见性:当一个线程修改了
volatile
变量,其他线程可以立即感知。 - 禁止重排序:确保程序执行顺序符合预期。
- 可见性:当一个线程修改了
底层实现原理
内存屏障:通过内存屏障(Memory Barrier)实现:
- 写操作后插入 Store 屏障,强制刷新到主内存。
- 读操作前插入 Load 屏障,强制从主内存加载最新值。
🔥 关注【码间烟火录】,解锁秋招通关秘籍! 🔥
🎯 这里有你想要的一切:
✅ 超全秋招经验分享
✅ 高频八股问题解析
✅ 最新大厂面经合集
✅ 海量技术干货
本文由mdnice多平台发布
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。