作者介绍

🎓 浙江大学软件工程硕士生

💻 淘天后端研发工程师

😇 秋招斩获阿里、字节、快手、京东、美团等多个大厂研发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 缓存热点数据,减少数据库压力。
    • 异步处理:异步处理订单生成,提升系统吞吐量。

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 通过 setget 方法操作线程的 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 进行包装,性能较低。
  • 区别

    • 性能:ConcurrentHashMap 性能最优,适合高并发场景。
    • 锁粒度:HashtablesynchronizedMap 锁粒度较大,性能较差。

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多平台发布


码间烟火录
1 声望0 粉丝

多个大厂后端ssp选手,浙江大学硕士,全网同号【码间烟火录】,持续分享技术干货~