2026.4.25 面经学习第三天

雪花算法

主要用于生成全局唯一ID,并且长用来作为数据表主键 雪花算法=符号位+时间戳+机械码+序列号 优点是性能高,不依赖数据库,天然支持分布式 缺点是会有时钟回拨产生重复ID和序列号溢出的风险

时钟回拨问题怎么解决?

检测并阻塞

当检测到当前时间 < 上一次时间时,直接拒绝或阻塞,等待时间追平。这里的等待时间追平是指系统时间追上一次生成ID的时间

多时钟序列

引入“时钟版本号”(clockId),时间回拨时切换 clockId 保证不同时间段生成的 ID 不冲突(类似逻辑分片)

序列号溢出怎么解决

等待下一毫秒

当序列号用完,阻塞到下一毫秒再继续生成这是默认实现,简单且可靠

扩展序列号位数

增加序列号 bit 数(例如从 12 bit → 14 bit代价是会压缩时间戳或机器位

为什么选择RabbitMQ

选择 RabbitMQ,不是因为它一定比 Kafka 更强,而是因为我的场景更偏业务异步任务,需要可靠投递、消费确认、失败重试和死信队列。RabbitMQ 功能足够成熟,接入成本也比较低,所以更合适。

定时调度任务

定时调度任务主要用于按固定时间或固定周期自动执行后台逻辑

Spring的定时任务

先在启动类上开启定时任务

@EnableScheduling
@SpringBootApplication
public class Application {
}

然后在方法上加 @Scheduled

@Component  
public class TaskJob {  
  
    @Scheduled(cron = "0 0/5 * * * ?")  
    public void run() {  
        System.out.println("每 5 分钟执行一次");  
    }  
}

@Scheduled的参数

@Scheduled(fixedRate = 5000) 从任务开始时间算,每隔 5 秒触发一次。 @Scheduled(fixedDelay = 5000) 从任务结束时间算,任务执行完后,再等 5 秒触发下一次。 @Scheduled(initialDelay = 3000, fixedRate = 5000) 项目启动后先等 3 秒,再每隔 5 秒执行一次。 @Scheduled(cron = "0 0/5 * * * ?") 使用 cron 表达式,这里表示每 5 分钟执行一次。 @Scheduled(zone = "Asia/Shanghai", cron = "0 0 2 * * ?")

Redis的淘汰策略

noeviction
不淘汰,直接报错(写失败) volatile 系列(只淘汰设置了过期时间的 key)

  • volatile-lru:淘汰最近最少使用
  • volatile-lfu:淘汰使用频率最低
  • volatile-random:随机淘汰
  • volatile-ttl:淘汰即将过期的

allkeys 系列(淘汰所有 key)

  • allkeys-lru:最常用(推荐)
  • allkeys-lfu
  • allkeys-random lru 最近最少使用,lfu最不常用

多租户设计

多租户设计就是一套系统支持多个租户使用,并保证租户之间的数据隔离。常见方案有独立数据库、独立 Schema、共享数据库共享表。独立数据库隔离性最好但成本高,共享表成本最低但要重点防止数据串租。实际项目中常用共享表方案,在业务表中增加 tenant_id,登录后从 Token 中解析 tenant_id 放入上下文,通过 MyBatis 拦截器或 MyBatis-Plus 多租户插件自动给 SQL 拼接 tenant_id 条件,同时结合权限控制、联合索引和数据校验来保证安全和性能。

RAG的流程

alt

Java的内存模型

JMM是一套并发编程规范,核心是解决并发场景下共享变量的可见性、有序性和原子性问题。

可见性

一个线程对变量的修改,其他线程是否能立即看到 实现:

  • volatile
    写操作会刷新到主内存,读操作会从主内存读取
  • synchronized
    释放锁前会把工作内存刷新到主内存,获取锁会重新读取 注意:volatile只保证有序性和可见性,不保证原子性 对于volatile修饰的变量x,x++、++x、x+=1都不是原子操作

有序性

代码执行顺序是否符合预期

  • happens-before 规则(核心)
  • volatile:禁止指令重排(部分)
  • synchronized:通过内存屏障保证顺序

原子性

操作是否不可被中断

  • synchronized:保证临界区原子性
  • Lock(如 ReentrantLock)
  • CAS(Atomic 类,如 AtomicInteger)

volatile的实现原理

可见性: 1)JVM 会在写操作后插入写屏障 2)强制把 CPU 缓存中的数据刷新到主内存volatile 变量时: 1)JVM 会在读操作前插入读屏障 2)使 CPU 缓存失效,从主内存重新加载 有序性: volatile 会禁止特定的指令重排:

  • 写 volatile 之前的操作不能排到它后面
  • 读 volatile 之后的操作不能排到它前面

happens-before常见规则

1)程序顺序规则

同一个线程内,代码按顺序执行
前面的操作 happens-before 后面的操作

2)volatile 变量规则

对一个 volatile 变量的写
happens-before
后续对该变量的读

3)锁规则(monitor)

解锁(unlock)
happens-before
后续加锁(lock)

4)传递性(重要)

如果: A happens-before B
B happens-before C 那么: A happens-before C

栈溢出的情况

  • 递归没有终止条件
  • 递归层级过深
  • 栈帧过大

对象创建的步骤

1)类加载检查

当执行 new 时,先检查类是否已被加载
如果没有,会触发类加载(加载 → 验证 → 准备 → 解析 → 初始化)

2)分配内存

在堆中为对象分配内存 方式有两种:

  • 指针碰撞(堆内存规整)
  • 空闲列表(堆内存不规整)

3)初始化零值

把分配的内存初始化为默认值(0、null、false)

4)设置对象头

包括:

  • Mark Word(哈希、锁信息、GC 年龄等)
  • 类型指针(指向类元数据)

5)执行构造方法(init)

执行 <init> 方法,按代码逻辑赋值

6)引用赋值(关键)

把对象地址赋值给引用变量

注意

指令重排问题

对象创建不是完全有序的,可能发生: 1)分配内存
2)初始化对象
3)引用指向内存 可能被重排为: 1)分配内存
3)引用指向内存
2)初始化对象

如何判断对象已经死亡

  1. 引用计数器:对象每被引用一次 +1,引用失效 -1,为 0 时表示可回收。优点是实现简单,缺点是无法解决循环引用
  2. 可达性分析:从一组 GC Roots 出发,向下搜索引用链:
  • 能被访问到 → 存活
  • 不能被访问到 → 判定为可回收对象

GC Roots 常见有哪些

  • 栈中引用(方法局部变量)
  • 方法区中的静态变量
  • 常量池引用
  • JNI(本地方法)引用

GC

GC 是 JVM 自动管理内存的机制,负责回收不再使用的对象,防止内存泄漏

常见的垃圾回收算法

1)标记-清除(Mark-Sweep)

标记垃圾对象 → 直接清除 缺点:产生内存碎片

2)标记-整理(Mark-Compact)

标记后把存活对象向一端移动 优点:无碎片
缺点:有移动成本

3)复制算法(Copying)

把内存分两块,每次只用一块
存活对象复制到另一块 优点:无碎片、效率高
缺点:空间浪费

分代回收

分代回收的核心思想是:根据对象存活时间不同,采用不同回收策略,提高 GC 效率因为大多数对象具有“朝生夕死”的特点。

不同对象生命周期不同:

  • 新创建的对象 → 大概率很快被回收
  • 存活较久的对象 → 很少被回收 如果统一用一种算法,效率会很低,新生代使用复制算法,老年代使用标记整理+标记清除

STW在GC中是否必须

STW:在进行某些操作时,暂停所有用户线程(业务线程),只让 GC 线程执行。说是GC停顿更容易理解一点 STW必须存在,但可以尽量缩短时间

为什么必须 STW

1)保证对象引用关系一致
如果 GC 时用户线程还在修改对象引用,会导致:

  • 可达性分析结果不准确
  • 出现“误回收”或“漏回收” 2)保证内存安全
    避免对象在回收过程中被修改,导致数据不一致

能不能完全没有 STW

不能完全消除,但可以减少:

  • Serial / Parallel:STW 时间较长
  • CMS:并发标记和清除,减少停顿
  • G1:通过分区回收,控制停顿时间

常见的GC回收器

1)Serial / Serial Old(串行)

特点:

  • 单线程回收
  • GC 时完全 STW(Stop-The-World)
  • 实现简单 算法:
  • 新生代:复制
  • 老年代:标记-整理 适用:
  • 小堆内存、单核环境

2)ParNew(新生代并行)

特点:

  • Serial 的多线程版本
  • 仍然 STW,但速度更快 典型搭配:
  • 常与 CMS垃圾回收器 一起使用

3)Parallel Scavenge / Parallel Old(吞吐量优先)

特点:

  • 多线程并行 GC
  • 关注 吞吐量(Throughput)
  • 仍然 STW 适用:
  • 批处理、计算型任务

4)CMS(Concurrent Mark Sweep)

CMS垃圾回收器 目标:

  • 最小化停顿时间 流程:
  • 初始标记(STW短暂)
  • 并发标记
  • 重新标记(STW)
  • 并发清除 问题:
  • 内存碎片
  • 并发失败(退化为 Full GC)
  • 已逐步被替代

5)G1(Garbage First,主流)

G1 将堆划分为多个大小相等的 Region,在并发标记阶段统计各 Region 的存活情况,在 Mixed GC 时按照回收收益进行排序,并在用户设定的停顿时间目标内选择一部分 Region 进行回收,从而实现可预测的停顿时间。 核心:

  • Region 分区
  • 优先回收垃圾最多的区域 特点:
  • 可控停顿时间
  • 混合回收(新生代 + 老年代)
  • 并发 + 局部 STW 适用:
  • 大多数服务端应用(默认)

6)ZGC(低延迟,了解)

ZGC垃圾回收器 特点:

  • 几乎全并发
  • 停顿时间极低(毫秒级)
  • 使用着色指针 适用:
  • 超大堆、对延迟敏感系统

7)Shenandoah(低延迟,了解)

Shenandoah垃圾回收器 特点:

  • 并发标记 + 并发整理
  • 停顿时间稳定

面经地址

https://www.nowcoder.com/feed/main/detail/a4238678a5d743fbb8c4fd4eada85ab3?sourceSSR=users

#面经#
每日面经记录 文章被收录于专栏

记录每天Java和Agent面经学习

全部评论

相关推荐

头像
昨天 18:51
已编辑
华东师范大学 算法工程师
暑期实习从2月开始投,面了两个月,流程该挂的都挂完了,腾讯字节一共号称是1.7w个hc,不知道都发给谁了,估计今年秋招要难顶。Timeline米哈游、美团、蚂蚁、微软等公司直接简历挂穿,没进面。携程:3.3&nbsp;投递、测评3.12&nbsp;笔试3.18&nbsp;一面3.25&nbsp;二面4.13&nbsp;ai面(hr面)4.14&nbsp;英语测评4.23&nbsp;offer(已拒)腾讯:2.6&nbsp;测评2.28&nbsp;wxg一面3.5&nbsp;wxg二面(挂)3.11&nbsp;teg一面3.21&nbsp;teg二面(取消)3.31&nbsp;teg一面4.10&nbsp;teg二面(挂)4.21&nbsp;wxg一面4.24&nbsp;wxg二面(挂)字节:1.28&nbsp;aml约面(取消)3.17&nbsp;火山一面(挂)4.8&nbsp;aml一面(挂)4.20&nbsp;抖音data一面(挂)阿里:3.23&nbsp;投递、测评3.28&nbsp;笔试3.31&nbsp;淘天一面4.8&nbsp;钉钉一面4.9&nbsp;淘天二面4.10&nbsp;阿里控股一面4.12&nbsp;钉钉二面(取消)4.15&nbsp;淘天hr面4.16&nbsp;淘天offer(已接)4.21&nbsp;高德一面(取消)4.22&nbsp;淘宝闪购一面(取消)面试最大的感触是,现在撞上ai转型,一堆老业务急着转向,新业务非常不成熟,研究型的组bar非常高根本进不去,业务侧挂着算法的岗位干的都是工程活,面试却又要问算法,另外agent的落地也远没有那么广,绝大多数还是那套写死的系统调一下llm&nbsp;api或者做做rag,其余少部分真的在搭agent的,基本不能在线上服务用什么很智能的模型,现阶段成本太高,进去大概率就是给垃圾模型从工程方面兜底,除了业务场景的应用和数据经验以外,技术方面很难有什么提升。算法岗做不了基模的还是去搜广推好,之前判断失误了完全没投,秋招不知道还进不进得去。
我的求职进度条
点赞 评论 收藏
分享
04-24 18:13
南京大学 Java
点赞 评论 收藏
分享
大愣子衰哥:老哥,是正式还是实习
点赞 评论 收藏
分享
拼多多暑期octimeline:拼多多服务端研发3.15&nbsp;笔试3.21&nbsp;一面4.1&nbsp;&nbsp;&nbsp;二面挂4.10&nbsp;一面4.17&nbsp;HR面4.23&nbsp;oc字节跳动在官网上投没反应,但是之前忽然看到个内推码,投了以后是日常实习,时间不合适。但是简历进了人才库,都是hr微信找我来面试的,由此开始了奇妙之旅。字节内部运转的很高效,佩服。3.16&nbsp;一面3.20&nbsp;二面挂4.15&nbsp;一面4.16&nbsp;二面4.20&nbsp;HR面&nbsp;&nbsp;HR面过了,但是承认有个拼多多的hr面也过了,字节表示需要明确选字节才走hc审批。部门很好,流程很快,但是权衡之下还是拒了。京东测开3.6&nbsp;&nbsp;&nbsp;一面3.9&nbsp;&nbsp;&nbsp;二面挂3.25&nbsp;一面挂(金融支付的测开面试官好凶,一问三不知,快要自闭了)美团(美团大BOSS~~)3.14&nbsp;笔试3.26&nbsp;小象超市一面挂3.30&nbsp;DAG引擎一面挂4.9&nbsp;&nbsp;&nbsp;金融业务一面挂4.17&nbsp;本地商业中台一面过然而并没有什么用,没回人才库,也没二面。感谢美团认可我,让我过一面。三次一面挂,一次一面过,屡败屡战,屡战屡败。美团提高了我的认知,磨炼了我的意志,美团万岁!OPPO3.31&nbsp;一面挂oppo的一面挂极大地刺激到了我,oppo不考笔试,只考项目,一直以为是大厂招聘要求高,原来是我太菜,我开始反思自己的不足之处,疯狂用ai升级项目,自救。感恩OPPO,点醒了沉睡的人蚂蚁集团3.19&nbsp;ai&nbsp;coding3.31&nbsp;一面挂&nbsp;&nbsp;这是一场kpi面,面试官没有开摄像头。3.31下午的OPPO,3.31晚上的蚂蚁kpi,让我彻底意识到自己的菜。虽然是一场kpi面,但是我忍了一个小时之后,等到反问环节,向面试官求助,请求指出我的问题在哪里。问题很多,面试官一针见血地指出了一个问题。我决定升级一下项目,而不是停留在学习项目、demo项目。但是第二天4.1上午10:00就是拼多多二面,我还没重构多少,就带着绝望的心情面拼多多。面到15min,我之前的玩具项目就被面试官问穿了,心态崩了,直接请求面试官给我的项目一点建议,指出我的问题,给点改进的方向。面试官很生气,说面试还没有结束,这种话本不应该现在说。但是既然说了,他还是指出了我的问题,给了几条建议、指点。最后还指出我不仅要提高项目,还要练习语言表达能力。感恩拼多多,彻底被多多征服了携程集团3.13&nbsp;&nbsp;笔试4道ac&nbsp;从此进入人才库阿里巴巴一开始不怎么会agent,没敢投。4.21&nbsp;测评4天后才笔试,下周一才面AI&nbsp;SRE,面着玩吧。华为软开4.8&nbsp;&nbsp;&nbsp;笔试4.10&nbsp;心理测评挂&nbsp;&nbsp;刚刚燃起的希望又幻灭了,“点击即送”的都没有把握住,又是一个小低谷。华为,我对你有了新的认识。招银网络4.15&nbsp;测评4.23&nbsp;一面&nbsp;今天刚面完,不知道结果同花顺4.15笔试、测评4.23喜提感谢信&nbsp;&nbsp;同花顺笔试还挺有意思海康威视4.16笔试、测评&nbsp;&nbsp;后续没反应简历挂:快手、哔哩哔哩、米哈游、美的集团、小米集团、滴滴、SHEIN总体来讲3.31-4.1痛苦达到了峰值,不在低谷中爆发,就在低谷中灭亡。求职好难,还过的去的bg让我在白板状态下也能获得面试机会,打了一年leetcode周赛让我对笔试和手撕无所畏惧,获得了有笔试门槛的公司的机会(拼多多、美团)。但是机会来了,面对机会,要想办法把握住。祝牛友们求职顺利,我这种水平一般的都能找到暑期,现在没找到的、还在煎熬着的牛友们也一定能行,不要放弃
江海寄余生Y:pdd挂了还可以捞嘛
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务