Java 面试备战 · 完整版
覆盖并发、JVM、Spring、MySQL、Redis、分布式、微服务、Docker、LangChain4j 等 14 大专题。
点击题目展开答案,背熟后点右上角 ✓ 标记掌握。面试前一天只看未掌握项。
Java 并发、线程与锁
进程是操作系统资源分配的基本单位,拥有独立地址空间、文件句柄;线程是 CPU 调度的基本单位,同一进程的线程共享堆和方法区,各自有独立的程序计数器、虚拟机栈。
- 资源:进程独立,线程共享。
- 切换开销:进程要切页表、刷 TLB,开销大;线程只保存寄存器和栈指针,开销小。
- 通信:进程间需 IPC;线程直接读写共享变量。
- 崩溃影响:进程隔离,一个崩溃不影响其他;线程崩溃可能拖垮整个进程。
- 继承 Thread:无法再继承其他类,不推荐。
- 实现 Runnable:任务与线程解耦,推荐,但无返回值。
- 实现 Callable + FutureTask:有返回值、能抛异常。
- 使用线程池:生产环境首选,复用线程、控制并发、统一管理。
- NEW:新建,未调用 start()。
- RUNNABLE:可运行,包含 OS 的就绪和运行中。
- BLOCKED:等待 synchronized 锁。
- WAITING:无限等待,wait/join/park。
- TIMED_WAITING:超时等待,sleep(ms)/wait(ms)。
- TERMINATED:终止。
| 方法 | 所属 | 是否释放锁 | 唤醒方式 |
|---|---|---|---|
| sleep | Thread 静态 | 否 | 时间到自动醒 |
| wait | Object 实例 | 是 | notify/notifyAll |
| yield | Thread 静态 | 否 | 提示调度器让出 CPU |
| join | Thread 实例 | 是(内部 wait) | 目标线程结束 |
不要用 Thread.stop(),会导致锁突然释放、数据不一致。推荐中断标志 + 循环检查:
while (!Thread.currentThread().isInterrupted()) {
// 业务逻辑
}
interrupt()只是设置中断标志,不强制终止。- 阻塞方法(sleep/wait/join)会抛 InterruptedException 并清除标志。
- 捕获后恢复标志:
Thread.currentThread().interrupt()。 - 可配合 volatile boolean 标志位。
多线程并发访问共享可变状态,程序结果始终正确。线程不安全来自原子性、可见性、有序性三个问题。
五种保证方式- 不可变:final、String、LocalDate。
- 互斥同步:synchronized、ReentrantLock。
- 非阻塞同步:CAS、AtomicInteger。
- 线程封闭:ThreadLocal、局部变量。
- 无共享:每线程独立处理再合并。
- volatile:保证可见性、有序性,不保证原子性。底层内存屏障,写后刷回主内存,读前从主内存加载。
- synchronized:保证原子性、可见性、有序性。代码块用 monitorenter/monitorexit,方法用 ACC_SYNCHRONIZED。
- 锁升级:无锁 → 偏向锁 → 轻量级锁 → 重量级锁。
JMM定义了线程与主内存的交互:每个线程有工作内存,变量从主内存拷贝副本操作,再写回主内存。
happens-before 八条规则- 程序顺序:同线程内前面 hb 后面。
- 监视器锁:解锁 hb 后续加锁。
- volatile:写 hb 后续读。
- 线程启动:start() hb 线程内所有操作。
- 线程终止:线程内所有操作 hb 其他线程检测到终止。
- 线程中断、对象终结、传递性。
CAS:比较并交换,V==A 时更新为 B,由 CPU 指令保证原子性。
三大问题- ABA:值从 A 变 B 又变 A,CAS 察觉不到。解决用
AtomicStampedReference加版本号。 - 自旋开销:失败一直重试,CPU 空转。用 LongAdder 分段减少竞争。
- 只能保证单个变量:多变量用 AtomicReference 封装。
核心:volatile int state + CLH 双向队列。ReentrantLock、Semaphore、CountDownLatch 都基于 AQS。
加锁流程- CAS 修改 state,成功则获取锁。
- 失败封装成 Node 入队,LockSupport.park 阻塞。
- 前驱释放后 unpark 唤醒后继。
两种模式:独占(ReentrantLock)和共享(Semaphore、CountDownLatch)。
7 参数:corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。
执行流程- 线程数 < core,创建核心线程。
- 核心满,任务入队列。
- 队列满,创建非核心线程。
- 达到 max,触发拒绝策略。
拒绝策略:Abort(抛异常)、CallerRuns(调用者执行,反压)、Discard(丢弃)、DiscardOldest(丢最老的)。
线程数:CPU 密集 N+1;IO 密集 2N 或 QPS×耗时;最终以压测为准。
方案:分批读取 + 自定义线程池 + CompletableFuture 并行 + 汇总落库。
- DB 分批读简历,每批 100 条。
- 提交线程池,supplyAsync 并行解析、匹配、评分。
- allOf 等待全部完成,汇总批量落库。
注意:子线程事务失效需编程式事务;异常必须捕获;结果落库用唯一索引 + Redis 去重保证幂等;控制并发度防打爆连接池。
原理:每个 Thread 有 ThreadLocalMap,key 是 ThreadLocal 弱引用,value 强引用。get/set 操作当前线程自己的 map,天然隔离。
泄漏原因:ThreadLocal 被 GC 后 key 变 null,value 无法访问也无法释放;线程池场景下线程长期存活,泄漏累积。
解决:用完必须 remove(),通常放 finally;ThreadLocal 定义为 static final。
应用:用户上下文、traceId、事务连接绑定。
四个条件:互斥、请求与保持、不可剥夺、循环等待。
预防:统一加锁顺序;tryLock 超时;减少锁粒度。
排查:jstack <pid> 输出 "Found one Java-level deadlock",列出线程、锁对象、等待关系。jconsole 也能检测。
- 偏向锁:一个线程反复获取,把线程 ID 记在 Mark Word,之后同线程直接通过。JDK15 后废弃。
- 轻量级锁:第二个线程竞争时升级,线程在栈帧建 Lock Record,CAS 指向它,适合竞争不激烈。
- 重量级锁:CAS 自旋失败后升级,基于 OS mutex,未获取的线程挂起。
锁状态在 Mark Word 的 2 位标志:01 无锁/偏向、00 轻量级、10 重量级、11 GC。
| 维度 | synchronized | ReentrantLock |
|---|---|---|
| 实现 | JVM 关键字 | JUC 类,基于 AQS |
| 释放 | 自动 | 手动 unlock(finally) |
| 可中断 | 否 | lockInterruptibly 支持 |
| 超时 | 否 | tryLock(timeout) 支持 |
| 公平性 | 非公平 | 可选公平/非公平 |
| 条件变量 | 一个 wait/notify | 多个 Condition |
分离读锁和写锁:读读不互斥、读写互斥、写写互斥。AQS 的 state 高 16 位表示读锁数量,低 16 位表示写锁重入次数。
适合读多写少的缓存场景,但要注意写饥饿——大量读可能让写线程一直拿不到锁。StampedLock 提供乐观读,性能更好。
- 悲观锁:假设一定冲突,先加锁。synchronized、Lock、select for update。适合写多。
- 乐观锁:假设冲突少,先操作后校验。CAS、version 字段。适合读多。
update product
set stock = stock - 1, version = version + 1
where id = #{id} and version = #{version}
- ConcurrentHashMap:JDK8 用 CAS + synchronized 锁桶头。
- CopyOnWriteArrayList:写时复制,读多写少。
- ConcurrentLinkedQueue:CAS 无锁队列。
- BlockingQueue:ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、PriorityBlockingQueue、DelayQueue。
- LongAdder:分段累加,高并发计数优于 AtomicLong。
JVM 虚拟机
- 线程私有:程序计数器、虚拟机栈、本地方法栈。
- 线程共享:堆、方法区(JDK8 后元空间)。
- 堆分区:新生代(Eden + 2 Survivor 8:1:1)、老年代 1:2。
常见 OOM:堆溢出、元空间溢出、栈溢出、直接内存溢出。
引用计数法无法解决循环引用,JVM 不用。
可达性分析:从 GC Roots 出发不可达即可回收。
GC Roots:栈局部变量、静态变量、常量、本地方法栈、活跃线程、同步锁对象。
三大算法:标记-清除(碎片)、标记-复制(浪费空间)、标记-整理(移动成本)。
分代:新生代用复制,老年代用标记-清除/整理。晋升条件:年龄 15、Survivor 放不下、大对象直接进老年代。
- Serial:单线程,客户端。
- Parallel:多线程吞吐量优先,JDK8 默认。
- CMS:并发标记清除,低停顿,有碎片,JDK9 废弃。
- G1:分 Region,可预测停顿,JDK9 后默认。
- ZGC:染色指针,停顿 <10ms,大堆。
过程:加载 → 验证 → 准备 → 解析 → 初始化。
双亲委派:先交父加载器,保证核心类安全、避免重复加载。
打破:SPI(线程上下文类加载器)、Tomcat 隔离、OSGi。
- top 找进程 PID。
- top -Hp pid 找线程 TID。
- printf "%x" tid 转十六进制。
- jstack pid | grep -A 30 十六进制 定位代码。
启动加 -XX:+HeapDumpOnOutOfMemoryError,用 MAT 分析支配树。工具:jps、jstat、jmap、jstack、Arthas。
Spring / SpringBoot / SpringMVC
IoC:控制反转,对象创建和依赖注入交给容器。DI 是具体实现。
AOP:面向切面,日志、事务、权限、缓存从业务抽离。底层 JDK 动态代理(有接口)+ CGLIB(无接口)。
实例化 → 属性注入 → Aware 接口 → BeanPostProcessor 前置 → InitializingBean/@PostConstruct → BeanPostProcessor 后置(AOP 代理在此生成)→ 使用 → 销毁。
三级缓存:singletonObjects、earlySingletonObjects、singletonFactories。
流程:创建 A → 实例化后把工厂放入三级 → 注入 B → 创建 B → B 注入 A 时从三级拿工厂生成早期引用 → B 完成 → A 完成。
限制:只解决单例 setter/字段注入,构造器注入和 prototype 无法解决。
- REQUIRED(默认):有则加入,无则新建。
- REQUIRES_NEW:总是新建,挂起当前。
- NESTED:嵌套,内层可独立回滚。
- 其他:SUPPORTS、NOT_SUPPORTED、MANDATORY、NEVER。
- 方法非 public。
- 自调用(this 调用),绕过代理。
- 异常被 catch 未抛出。
- 抛受检异常但未配 rollbackFor。
- 数据库引擎不支持(MyISAM)。
- 多线程中调用。
@SpringBootApplication → @EnableAutoConfiguration → 读取 spring.factories 或 AutoConfiguration.imports → 条件注解筛选(@ConditionalOnClass、@ConditionalOnMissingBean)→ 注入 Bean。
MySQL 与 SQL 优化
重点看:type、key、rows、Extra。
- type:system > const > eq_ref > ref > range > index > ALL。至少到 range/ref。
- key:实际用的索引,null 表示没用。
- rows:预估扫描行数,越小越好。
- Extra:Using index 好;Using filesort、Using temporary 需优化。
- 对索引列用函数:where date(create_time)='2024-01-01'。
- 隐式类型转换:字符串字段传数字。
- 前导模糊:like '%关键词'。
- or 部分无索引。
- 不满足最左前缀。
- 范围条件后索引失效:a=1 and b>2 and c=3,c 用不到。
慢的原因:limit 100000,20 会扫描并丢弃前 100000 行。
- 游标分页:where id > #{lastId} order by id limit 20。
- 延迟关联:先查主键再 join 回表。
- 覆盖索引:先查主键再回表。
- 业务限制:禁止跳页,只允许下一页。
- 架构:搜索走 ES,冷数据归档。
ACID:原子性、一致性、隔离性、持久性。
四种隔离级别:读未提交、读已提交、可重复读(MySQL 默认)、串行化。
问题:脏读、不可重复读、幻读。
MVCC:undo log 版本链 + ReadView。RC 每次查询生成 ReadView,RR 首次生成并复用。解决不可重复读,幻读靠间隙锁。
对比 B 树:B+ 非叶子只存键,树矮 IO 少;叶子链表连接,范围查询快。
对比哈希:哈希等值 O(1),但不支持范围、排序、最左前缀。
联合索引 (a,b,c),查询条件必须从 a 开始连续匹配。
- a=1:用 a。
- a=1 and b=2:用 a、b。
- b=2 and c=3:不用。
- a=1 and b>2 and c=3:用 a、b,c 用不到。
定位:慢查询日志、mysqldumpslow、pt-query-digest、performance_schema、explain。
优化:联合索引、覆盖索引、索引下推;子查询改 join、延迟关联、分页优化;减少回表;读写分离、缓存、归档、分库分表。
主库写 binlog → 从库 IO 线程拉取 → relay log → SQL 线程回放。
延迟解决:并行复制(MTS)、拆大事务、半同步、强一致读走主库。
Redis 缓存
- String:缓存、计数器、分布式锁。
- Hash:对象属性、购物车。
- List:消息队列、最新列表。
- Set:去重、共同好友、抽奖。
- ZSet:排行榜、延时队列、滑动窗口限流。
- Bitmap/HyperLogLog/GEO/Stream:签到、UV、附近的人、消息队列。
- 穿透:查不存在数据打 DB。解决:布隆过滤器、缓存空值、参数校验。
- 击穿:热点 key 过期打 DB。解决:互斥锁重建、逻辑过期、热点永不过期。
- 雪崩:大量 key 同时过期或 Redis 宕机。解决:过期时间加随机、多级缓存、集群、熔断降级。
推荐:先更新 DB,再删缓存(Cache Aside)。
加强:延迟双删、Canal 订阅 binlog 异步删、分布式锁、过期时间兜底。
加锁:SET key value NX PX 30000,value 唯一。
释放:Lua 脚本比较 value 再删,防误删。
续期:Redisson 看门狗,默认 30 秒,每 10 秒续期。
坑:锁过期业务未完成、误删、主从切换丢锁、不可重入。
- 纯内存操作。
- IO 多路复用(epoll)。
- 单线程命令执行,无锁竞争。
- 高效数据结构。
- Redis 6.0 后网络 IO 多线程,命令执行仍单线程。
过期删除:惰性删除 + 定期删除。
淘汰策略:noeviction、allkeys-lru/lfu/random、volatile-lru/lfu/random/ttl。缓存推荐 allkeys-lru。
- 主从:读写分离,手动故障转移。
- 哨兵:自动故障转移 + 监控。
- Cluster:16384 槽分片,水平扩展。
大 key:拆分、Hash 分片、unlink 异步删除、scan。
热 key:本地缓存、多级缓存、key 加随机后缀、读写分离。
分布式基础
CAP:一致性、可用性、分区容错,分布式必须 P,取舍 C/A。
CP:ZK、Nacos 持久实例;AP:Eureka、Nacos 临时实例。
BASE:基本可用、软状态、最终一致。
- 2PC/3PC:强一致,阻塞、性能差。
- TCC:Try-Confirm-Cancel,侵入大。
- 本地消息表:业务与消息同事务,定时补偿。
- MQ 事务消息:RocketMQ 半消息 + 回查。
- Saga:长事务拆本地事务 + 补偿。
- 最大努力通知:支付回调。
- 唯一索引:DB 层兜底。
- 去重表:记录业务唯一标识。
- Redis Token:请求前获取,处理时原子删除。
- 状态机:只允许合法状态流转。
- 乐观锁:version 字段。
- 分布式锁:同业务 ID 串行。
- 固定窗口:INCR + EXPIRE,简单但有临界问题。
- 滑动窗口:ZSet 存时间戳,Lua 保证原子。
- 漏桶:恒定速率流出。
- 令牌桶:允许突发,Guava RateLimiter。
组件:Guava、Redis+Lua、Nginx limit_req、Sentinel。
- RabbitMQ TTL + DLX。
- Redis ZSet:score 存时间戳。
- Redisson DelayedQueue。
- 时间轮:Netty HashedWheelTimer。
- XXL-JOB、Quartz。
UUID、数据库自增、号段模式、雪花算法、Redis INCR。
雪花:1 符号 + 41 时间 + 10 机器 + 12 序列。趋势递增,需解决时钟回拨。
微服务架构与组件
- 单一职责:一个服务只做一件事。
- DDD 限界上下文划分。
- 高内聚低耦合。
- 独立部署、独立数据。
- 演进式拆分:先单体,痛点出现再拆。
雪崩:下游故障导致上游线程耗尽,连锁崩溃。
防护:超时控制、熔断、降级、隔离、限流、重试(幂等)、缓存。
- 限流:入口控流量,超阈值拒绝(预防)。
- 熔断:下游故障快速失败,给恢复时间(自保)。
- 降级:返回兜底结果(兜底)。
临时实例:心跳保活,AP(Distro),优先可用。
持久实例:主动探测,CP(Raft),优先一致。
推拉结合:客户端定时拉取 + 服务端 UDP 推送变更。
健康检查:5 秒心跳,15 秒未收到标记不健康,30 秒剔除。
长轮询:客户端发起 30 秒长轮询,服务端 hold 住。
变更通知:配置变化时立即响应,客户端拉取最新。
本地快照:客户端缓存配置,服务端不可用仍能启动。
刷新:@RefreshScope、@ConfigurationProperties。
扫描 @FeignClient → 动态代理生成实现 → 注解解析 → 编码 → LoadBalancer 选实例 → HTTP 调用 → 解码。
超时:connectTimeout、readTimeout。
重试:默认关闭,写接口必须幂等才能重试。
优化:替换为 OkHttp 连接池,开启 GZIP。
三大概念:Route、Predicate、Filter。
执行流程:请求 → HandlerMapping 匹配 → Pre 过滤器 → 转发下游 → Post 过滤器 → 响应。
限流:RequestRateLimiter + Redis 令牌桶。
注意:基于 WebFlux,不能引 spring-boot-starter-web。
功能:限流、熔断、降级、系统保护、热点参数、授权。
熔断状态机:关闭 → 打开 → 半开。
原理:SlotChain 责任链,依次执行 NodeSelector、ClusterBuilder、Statistic、Flow、Degrade。
- AT:无侵入,undo log 反向补偿,需主键。
- TCC:Try-Confirm-Cancel,业务侵入大。
- Saga:长事务拆本地事务,逆向补偿。
- XA:数据库 XA,强一致性能差。
三角色:TC(协调者)、TM(管理者)、RM(资源管理者)。
核心概念:TraceId、SpanId、ParentSpanId。
传递方式:HTTP Header / MQ 属性透传,MDC + ThreadLocal 记录日志。
方案:Sleuth+Zipkin、SkyWalking(字节码增强,无侵入)。
方案:网关统一鉴权 JWT/OAuth2,用户信息放 Header 透传。内部调用用内部 Token 或 mTLS。
权限模型:RBAC,注解 + AOP 接口级鉴权。
| 能力 | 推荐 |
|---|---|
| 注册/配置 | Nacos |
| 服务调用 | OpenFeign |
| 网关 | Spring Cloud Gateway |
| 熔断限流 | Sentinel |
| 分布式事务 | Seata |
| 链路追踪 | SkyWalking |
| 消息队列 | RocketMQ / RabbitMQ |
| 监控 | Prometheus + Grafana |
RabbitMQ 消息队列
作用:异步解耦、削峰填谷、最终一致。
选型:RabbitMQ 低延迟可靠;Kafka 高吞吐;RocketMQ 事务/延迟消息。
- 生产者:Confirm + Return 回调,失败重试。
- Broker:交换机、队列、消息都持久化。
- 消费者:手动 ACK,失败进死信。
- 兜底:本地消息表 + 定时补偿。
MQ 只能保证 at-least-once,需业务幂等:消息带唯一 ID;Redis SETNX 或唯一索引去重;状态机控制流转。
- 临时扩容消费者。
- 批量消费。
- 耗时操作异步化。
- 紧急转临时队列。
- 预防:队列深度监控 + 告警。
设计模式实践
- 策略 + 工厂:支付、推送、简历匹配。
- 状态:订单、合同、出入库状态。
- 责任链:审批、校验、简历筛选规则链。
- 模板方法:导入、对账。
- 观察者:Spring 事件、MQ 通知。
- 适配器:第三方支付、物流、IM 封装。
策略接口:PayStrategy,定义 pay()、refund()。
实现类:WechatPay、Alipay、OfflinePay。
工厂:PayStrategyFactory 用 Map 缓存所有策略 Bean,按类型返回。
好处:新增渠道只需加实现类,符合开闭原则。
结构:抽象 Handler 持有 next,每个节点处理自己的规则。
规则链:学历 → 工作年限 → 技能匹配 → 匹配度评分。
好处:规则可插拔,新增不影响其他节点。
Docker 与 Kubernetes
| 维度 | 容器 | 虚拟机 |
|---|---|---|
| 隔离 | 进程级 | 硬件级 |
| OS | 共享内核 | 独立 OS |
| 启动 | 秒级 | 分钟级 |
| 资源 | MB 级 | GB 级 |
| 隔离性 | 较弱 | 强 |
- Namespace:资源隔离(PID、NET、IPC、MNT、UTS、USER、CGROUP)。
- Cgroup:资源限制(CPU、内存、IO)。
- UnionFS:镜像分层,OverlayFS/AUFS。
调用链:docker CLI → dockerd → containerd → shim → runc → 容器进程。
分层:镜像由多个只读层组成,每条 Dockerfile 指令一层,共享底层节省空间。
CoW:容器读文件直接读下层;写文件先把文件复制到可写层再改,下层保持只读。
- CMD:默认命令,docker run 后面的参数会覆盖。
- ENTRYPOINT:入口命令,不会被覆盖,参数追加。
ENTRYPOINT ["java", "-jar", "/app.jar"] CMD ["--spring.profiles.active=prod"]
一个 Dockerfile 写多个 FROM,后面的阶段可以引用前面阶段的产物。构建阶段用完整镜像,运行阶段只用 JRE。
FROM maven:3.9-jdk-17 AS builder WORKDIR /build COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn package -DskipTests FROM eclipse-temurin:17-jre-alpine WORKDIR /app COPY --from=builder /build/target/*.jar app.jar ENTRYPOINT ["java", "-jar", "app.jar"]
效果:从 600MB 降到 150MB 左右。
- bridge(默认):docker0 网桥,NAT 访问外网。
- host:共享宿主机网络,性能好但端口冲突。
- none:无网络。
- container:共享另一容器网络。
- 自定义 bridge:支持 DNS 服务发现(推荐)。
- Volume:Docker 管理,存在 /var/lib/docker/volumes,推荐持久化。
- Bind Mount:挂宿主机任意路径,方便调试。
- tmpfs:内存挂载,重启丢失。
退出码 137 通常是 OOM。解决:
- 调整内存限制
--memory=2g。 - JVM 感知容器:
-XX:MaxRAMPercentage=75.0。 - 排查内存泄漏:dump 堆分析。
- 限制应用内存:本地缓存加大小限制。
- kube-apiserver:API 入口。
- etcd:KV 存储,保存集群状态。
- kube-scheduler:调度 Pod。
- kube-controller-manager:运行控制器。
- kubelet:节点代理,管理 Pod。
- kube-proxy:网络代理,Service 负载均衡。
- Container Runtime:containerd、CRI-O。
Ingress → Service → Deployment → ReplicaSet → Pod → Container。
- Pod:最小调度单位,一个或多个容器共享网络存储。
- Deployment:管理副本数和滚动更新。
- Service:稳定访问入口,ClusterIP/NodePort/LoadBalancer。
- Ingress:七层入口,HTTP/HTTPS 路由。
- livenessProbe:失败重启容器,检测死锁。
- readinessProbe:失败从 Service 摘除,不接收流量。
- startupProbe:慢启动应用,成功后其他探针生效。
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
kubectl set image deployment/myapp myapp=myapp:2.0 kubectl rollout status deployment/myapp kubectl rollout undo deployment/myapp --to-revision=2
LangChain4j 与 AI 应用
专为 Java 开发者设计的 LLM 集成框架,统一 API 集成 OpenAI、通义千问、Ollama 等模型。
解决的问题- 屏蔽模型提供商 API 差异。
- 声明式 AI Service,只写接口。
- 内置 RAG 流水线。
- Function Calling 工具调用。
- ChatMemory 多轮对话。
高层 API,定义 Java 接口,框架通过动态代理自动生成实现。
- 接口方法用 @SystemMessage 和 @UserMessage 声明提示词。
AiServices.builder(Interface.class)绑定 ChatModel、Memory、Retriever、Tools。- 注入接口直接调用。
RAG(检索增强生成):先检索相关文档片段,再拼到提示词中让模型基于真实文档回答,避免幻觉。
四步流水线- 文档摄入:加载 Markdown、PDF 等。
- 向量化存储:EmbeddingModel 转向量,存 EmbeddingStore。
- 检索:问题向量化,从向量库检索 Top-K。
- 生成:片段 + 问题发给 ChatModel 生成回答。
在 Java 方法上加 @Tool 注解,在 AI Service 中指定工具类,框架自动处理调用循环。
流程:LLM 返回 toolExecutionRequests → 执行工具 → 结果封装成 ToolExecutionResultMessage → 再发给模型 → 模型生成最终回答。
ChatMemory 管理多轮对话上下文。
MemoryId 会话隔离标识,方法参数上加 @MemoryId,不同用户对话互不干扰。
持久化:用 Redis 作为 ChatMemoryStore,重启后恢复上下文。
- 定义 AI Service 接口,接收简历文本和岗位描述。
- @SystemMessage 设定招聘经理角色和评分标准。
- @UserMessage 传入简历和 JD,输出结构化评分。
- 返回 CvReview 对象(score + feedback)。
工程化:线程池批量并行,Redis 去重 + 唯一索引幂等,异常重试。
效果:筛选工作量降低约 40%。
- 调整切片大小(500-1000 字符,重叠 10%-20%)。
- 调整 Top-K(3-10)。
- 设置相似度阈值 minScore。
- 元数据过滤。
- 重排序 ReRankingModel。
- 查询改写。
- 混合检索(向量 + 关键词)。
- Spring AI:与 Spring Boot 无缝集成,API 简洁,适合快速开发。
- LangChain4j:更灵活,支持复杂 RAG、Agent、多轮对话,适合复杂 AI 应用。
计算机网络
三次握手:SYN → SYN+ACK → ACK,确认双方收发能力。
四次挥手:FIN → ACK → FIN → ACK,全双工需分别关闭。
TIME_WAIT:2MSL,保证最后 ACK 到达,防止旧连接数据混淆。
HTTPS = HTTP + TLS/SSL,加密传输,防篡改防窃听。
握手:非对称加密交换密钥,之后对称加密通信。端口 80 / 443。
- select:数组,1024 限制,O(n) 轮询。
- poll:链表,无上限,仍 O(n)。
- epoll:红黑树 + 就绪链表,O(1) 回调,适合高并发。
Redis、Nginx、Netty 都用 epoll。
数据结构与算法
- 冒泡/选择/插入:O(n²)。
- 快排:平均 O(nlogn),最坏 O(n²),不稳定。
- 归并:O(nlogn),稳定,需额外空间。
- 堆排:O(nlogn),不稳定。
HashMap + 双向链表,O(1) 查找和增删。Java 可用 LinkedHashMap,重写 removeEldestEntry。
- 小顶堆:维护 K 个元素,O(n log K)。
- 分治 + 哈希:大文件拆分到多个小文件,分别求 Top K 再合并。
反转:pre/cur/next 三指针迭代。
环检测:快慢指针,相遇则有环;相遇后一指针回头,再次相遇即入口。
项目话术与速记
模板:背景是 X,数据量/QPS 是 Y,痛点是 Z;我用 A 技术解决 B 问题,指标提升 C%。
- 招聘系统:简历筛选人工工作量大。线程池并行 + LangChain4j + Redis 去重,筛选工作量降低 40%。
- 外包管理:考勤打卡重复、合同状态乱。Redisson 锁 + 唯一索引 + 状态机,效率提升 30%。
- 冷链仓储:出入库深分页慢。游标分页 + 延迟关联 + 覆盖索引,查询性能提升。
- 本地生活:支付回调重复。唯一索引 + 状态机 + Redis Token 保证幂等。
- 前端:按钮置灰、验证码。
- 网关:限流、黑名单。
- Redis:库存预热、Lua 原子扣减、SETNX 防重。
- MQ:异步下单,削峰填谷。
- DB:唯一索引防超卖,异步落库。
- 兜底:限流降级、库存回滚、对账补偿。
- 链路追踪定位慢服务。
- Arthas trace 定位慢方法。
- 检查慢 SQL、Redis 大 key、线程池满、GC 频繁、下游超时。
- 工具:SkyWalking、Arthas、Prometheus、慢查询日志。
- volatile:可见有序不原子。
- synchronized:原子可见有序,锁升级。
- 线程池:核心 → 队列 → 最大 → 拒绝。
- 深分页:游标、延迟关联、覆盖索引。
- type 排序:system > const > eq_ref > ref > range > index > ALL。
- 索引失效:函数、隐式转换、前导模糊、最左前缀。
- 缓存三兄弟:穿透、击穿、雪崩。
- 缓存一致:先更新 DB,再删缓存,延迟双删。
- 分布式锁:SET NX PX + Lua 释放 + 看门狗。
- 幂等:唯一索引、去重表、Redis Token、状态机。
- 限流:固定窗口、滑动窗口、漏桶、令牌桶。
- 延时任务:TTL+DLX、Redis ZSet、时间轮、XXL-JOB。
- Nacos:临时 AP,持久 CP。
- 配置刷新:长轮询 + 本地快照 + @RefreshScope。
- Feign:动态代理 + 负载均衡 + HTTP。
- Gateway:Route + Predicate + Filter,WebFlux。
- Sentinel:限流、熔断、降级,SlotChain。
- 雪崩防护:超时、熔断、降级、隔离、限流。
- Seata:AT 无侵入,TC/TM/RM。
- 雪花:1 + 41 + 10 + 12。
- MQ 不丢:Confirm + 持久化 + 手动 ACK。
- MQ 不重:唯一 ID + 幂等消费。
- Docker:Namespace + Cgroup + UnionFS。
- 镜像分层:COPY/RUN 每步一层,共享底层。
- 多阶段构建:构建和运行分离,600MB 降到 100MB。
- K8s:Pod + Deployment + Service + Ingress,探针三件套。
- LangChain4j:AiServices 接口,RAG 检索增强,@Tool 工具调用。