快手后端(AI 方向)日常一面
几乎没问AI相关的东西,Java八股没咋准备。。。
基本信息
- 岗位: Java 后端 / AI 应用开发
- 时长: 约 50 分钟
- 考察: Java 基础、线程池、MySQL、项目设计、并发控制、大数相乘。
一、自我介绍
二、Java 基础
Q:Error 和 Exception 的区别与共同点?
A: 二者都继承自 Throwable。Error 多为 JVM 或系统级严重问题,如 OutOfMemoryError,通常不建议业务代码处理;Exception 是程序运行中可处理的异常。Exception 分为受检异常(如 IOException)和非受检异常 / 运行时异常(RuntimeException)。
Q:Java 和 Go 的异常处理有什么区别?
A: Java 使用 try-catch-finally、throw/throws,异常可沿调用栈传播,并区分受检和非受检异常。Go 通常通过 (value, err) 返回值显式处理错误,使用 if err != nil 判断;panic/recover 仅适用于不可恢复的程序级故障。
三、Java 线程池
Q:ThreadPoolExecutor 的七个核心参数?
A: corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。
Q:线程池提交任务的执行流程?
A:
- 当前线程数小于核心线程数:创建核心线程执行;
- 否则任务进入阻塞队列;
- 队列满且线程数小于最大线程数:创建非核心线程;
- 队列满且达到最大线程数:执行拒绝策略。
Q:常见阻塞队列?
A: ArrayBlockingQueue(有界数组)、LinkedBlockingQueue(链表)、SynchronousQueue(不存储任务,直接交接)、PriorityBlockingQueue(优先级)、DelayQueue(延迟)。
Q:常见拒绝策略?
A: AbortPolicy(抛异常,默认)、CallerRunsPolicy(提交线程执行)、DiscardPolicy(丢弃)、DiscardOldestPolicy(丢弃最旧任务后重试)。
Q:CPU / IO 密集型任务如何设置线程数?
A: CPU 密集型通常接近 CPU 核数(常见为核数 + 1);IO 密集型因大量等待可配置更多线程,但应根据等待时间、CPU 核数及压测结果决定。不同类型任务应拆分线程池。
四、MySQL 索引
Q:MySQL 常见索引结构及特点?
A:
- B+ 树: InnoDB 主流结构;层高低、磁盘 IO 少,叶子节点链表支持范围查询。
- 哈希: 等值查询快;不支持范围、排序、模糊查询。
- 二叉搜索树 / 红黑树: 树高相对更高,磁盘 IO 更多,不适合数据库索引的页存储场景。
Q:100 亿条 int 数据的 B+ 树约几层?
A: 需要先说明页大小、索引项大小、指针大小、行大小等假设。以 InnoDB 默认 16KB 页估算,每页通常可容纳数百个索引项;B+ 树 3~4 层可覆盖千万至数十亿级数据,具体取决于聚簇 / 二级索引及数据行大小。
五、项目
Q:拍照搜索流程是什么?
Q:如何降低拍照搜索耗时?
Q:超时与失败如何设计,避免用户频繁重试?
六、额度扣减与并发控制
Q:余额仅够一次调用,并发 100 个请求时如何避免超额?
七、算法:大数相乘
Q:如何实现两个超长数字字符串相乘?
A: 使用长度为 m + n 的数组模拟竖式乘法:从低位开始两层循环相乘,将结果累加到对应位置并处理进位,最后去除前导零。
public static String multiply(String num1, String num2) {
if ("0".equals(num1) || "0".equals(num2)) return "0";
int[] result = new int[num1.length() + num2.length()];
for (int i = num1.length() - 1; i >= 0; i--) {
for (int j = num2.length() - 1; j >= 0; j--) {
int product = (num1.charAt(i) - '0') * (num2.charAt(j) - '0')
+ result[i + j + 1];
result[i + j + 1] = product % 10;
result[i + j] += product / 10;
}
}
StringBuilder sb = new StringBuilder();
int i = 0;
while (i < result.length && result[i] == 0) i++;
while (i < result.length) sb.append(result[i++]);
return sb.toString();
}
- 时间复杂度:
O(mn) - 空间复杂度:
O(m+n) - 注意字符转数字要减
'0'。