AI出题人给出的Java后端面经(十五)(日更)
文章摘要:本文整理了Java后端开发的核心面试题,涵盖多个技术领域。Java基础部分解析Optional.map()和flatMap()的区别;MySQL优化包括函数索引和死锁预防;Redis和Kafka部分讲解分布式锁续期和消息监控;JVM调优涉及G1GC和OOM诊断;并发编程包含线程池动态调整和事务批提交;Spring框架部分讨论事务失效场景和安全防护;大模型应用部分介绍输出解析和语义缓存。每
链接双端链表
目录
🔵 一、Java基础
题目:
-
Optional深度使用
解释Optional.map()与Optional.flatMap()的核心区别,为何在链式调用中flatMap能避免嵌套Optional<Optional<T>>?
答案:
Optional深度使用
// map() 导致嵌套Optional Optional<Optional<String>> nested = Optional.of("user") .map(s -> Optional.of(s.toUpperCase())); // flatMap() 解包嵌套 Optional<String> flat = Optional.of("user") .flatMap(s -> Optional.of(s.toUpperCase())); // 返回 Optional<String>区别:
map(Function):函数返回普通值 →Optional<T>
flatMap(Function):函数返回Optional<T>→ 自动解包
🗃️ 二、持久化层(MySQL 8.0)
题目:
-
索引失效分析
针对SELECT * FROM logs WHERE DATE(create_time) = '2025-08-16'全表扫描,如何通过函数索引优化性能?给出执行计划对比 -
死锁预防实战
高并发场景下,UPDATE account SET balance = balance - 100 WHERE user_id = ?和UPDATE account SET balance = balance + 100 WHERE user_id = ?发生死锁,如何通过调整事务隔离级别解决?
答案:
题目1:函数索引优化
-- 创建虚拟列+索引 ALTER TABLE logs ADD COLUMN create_date DATE AS (DATE(create_time)) VIRTUAL, ADD INDEX idx_create_date(create_date); -- 执行计划对比 EXPLAIN SELECT * FROM logs WHERE create_date = '2025-08-16'; -- 结果:Using index (索引覆盖扫描)优化效果:
优化前 优化后 全表扫描5.2s 索引扫描0.03s 题目2:死锁预防方案
-- 方案1:调整事务隔离级别 SET TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 方案2:统一更新顺序(按user_id排序) UPDATE account SET ... WHERE user_id IN (?,?) ORDER BY user_id;隔离级别影响:
级别 死锁概率 REPEATABLE-READ 高 READ-COMMITTED 低
⚙️ 三、中间件
a) Redis 6.2
题目:
设计分布式锁续期方案:如何用 Redisson 的 watchDog 机制实现锁自动续期?解释锁续期失败时的容错策略
b) Kafka 3.5
题目:
如何通过 ProducerInterceptor 实现消息发送的实时耗时统计?给出滑动窗口计算P99发送延迟的代码片段
答案:
a) Redis锁续期方案
RedissonClient redisson = Redisson.create(); RLock lock = redisson.getLock("order_lock"); lock.lock(30, TimeUnit.SECONDS); // 看门狗默认续期间隔=30/3=10秒 // 手动续期(容错策略) if (lock.isHeldByCurrentThread()) { lock.expire(30, TimeUnit.SECONDS); // 失败则异步重试 }续期机制:
后台线程每10秒检查持有锁的客户端是否存活
存活则重置TTL为30秒
客户端宕机时自动释放
b) Kafka延迟统
public class LatencyInterceptor implements ProducerInterceptor<String, String> { private final SlidingWindowReservoir reservoir = new SlidingWindowReservoir(1000); // 滑动窗口 @Override public ProducerRecord<String, String> onSend(ProducerRecord<String, String> record) { record.headers().add("start-time", System.currentTimeMillis()); return record; } @Override public void onAcknowledgement(RecordMetadata metadata, Exception exception) { long duration = System.currentTimeMillis() - new BigInteger(metadata.headers().lastHeader("start-time").value()).longValue(); reservoir.update(duration); // 计算P99 Snapshot snapshot = reservoir.getSnapshot(); double p99 = snapshot.get99thPercentile(); } }
🧠 四、JVM
题目:
-
Full GC预防
分析-XX:+UseG1GC下频繁Full GC的三种成因,如何通过-XX:G1ReservePercent和-XX:InitiatingHeapOccupancyPercent调优避免? -
OOM诊断实战
给出jcmd+jmap+MAT分析Metaspace溢出的完整命令链和MAT分析路径
答案:
题目1:Full GC预防
三大成因及解决方案:
晋升失败:
-XX:G1ReservePercent=15 # 增加保留空间(默认10%)并发模式失败:
-XX:InitiatingHeapOccupancyPercent=35 # 降低并发回收阈值大对象分配失败:
-XX:G1HeapRegionSize=16M # 增大Region大小题目2:Metaspace OOM诊断
# 1. 查看元空间使用 jcmd <pid> VM.metaspace # 2. 生成堆转储 jmap -dump:live,format=b,file=meta_oom.hprof <pid> # 3. MAT分析路径 Path To GC Roots → ClassLoader加载树 → 重复加载的代理类
⚡ 五、Java并发
题目:
-
线程池调优
当ThreadPoolExecutor出现任务堆积时,如何通过getQueue().size()和getActiveCount()动态调整corePoolSize? -
并发工具应用
如何用CountDownLatch实现多线程加载数据+统一提交事务?对比CompletableFuture.allOf()的性能差异
答案:
题目1:线程池动态调整
ThreadPoolExecutor executor = new ThreadPoolExecutor(...); // 监控线程 new Thread(() -> { while (true) { int queueSize = executor.getQueue().size(); int activeCount = executor.getActiveCount(); if (queueSize > 1000 && activeCount == executor.getMaximumPoolSize()) { executor.setCorePoolSize(executor.getCorePoolSize() + 5); // 扩容 } Thread.sleep(5000); } }).start();题目2:批事务提交
CountDownLatch latch = new CountDownLatch(THREAD_COUNT); List<Future<?>> futures = new ArrayList<>(); for (int i = 0; i < THREAD_COUNT; i++) { futures.add(executor.submit(() -> { try { loadData(); // 数据加载 } finally { latch.countDown(); } })); } latch.await(); // 等待所有加载完成 transaction.commit(); // 统一提交性能对比(万级数据):
方式 耗时 CountDownLatch320ms CompletableFuture290ms
🌱 六、Spring框架
题目:
-
事务失效场景
解释@Transactional在私有方法、未被代理类调用、异常类型错误等场景失效的原因,给出5种解决方案 -
安全加固实战
如何通过SecurityFilterChain配置登录接口的防暴力破解?给出Bucket4j集成方案 -
性能监控埋点
设计@Controller层统一监控:通过HandlerInterceptor记录每个API的P99响应时间到Prometheus
答案:
题目1:事务失效解决方案
失效场景 解决方案 私有方法 改为public/protected 未被代理类调用 通过AopContext获取代理对象 异常类型错误 添加 @Transactional(rollbackFor=Exception.class)多线程调用 使用 TransactionTemplate嵌套事务传播错误 检查 propagation设置题目2:防暴力破解
@Bean public SecurityFilterChain filterChain(HttpSecurity http) { http.formLogin() .and() .addFilterBefore(new RateLimitFilter(), UsernamePasswordAuthenticationFilter.class); } public class RateLimitFilter extends OncePerRequestFilter { private final Bucket bucket = Bucket.builder() .addLimit(Bandwidth.simple(5, Duration.ofMinutes(1))) // 1分钟5次 .build(); @Override protected void doFilterInternal(...) { if ("/login".equals(request.getRequestURI())) { if (!bucket.tryConsume(1)) { response.sendError(429, "请求过于频繁"); return; } } chain.doFilter(request, response); } }题目3:API监控埋点
public class MetricsInterceptor implements HandlerInterceptor { private final Timer timer = Timer.builder("api.latency") .publishPercentiles(0.5, 0.95, 0.99) .register(Metrics.globalRegistry); @Override public boolean preHandle(...) { request.setAttribute("startTime", System.nanoTime()); return true; } @Override public void afterCompletion(...) { long duration = System.nanoTime() - (long) request.getAttribute("startTime"); timer.record(duration, TimeUnit.NANOSECONDS); } }
🤖 七、大模型与AI整合(选修部分)
题目:
-
大模型输出控制
如何通过Spring AI的OutputParser将LLM返回的JSON自动转换为POJO?设计字段缺失时的降级策略 -
语义缓存优化
用Caffeine+Redis实现大模型响应的语义相似度缓存,设计基于Sentence-BERT的相似度计算方案 -
模型安全防护
在提示词预处理层,如何通过正则表达式过滤SELECT、DROP等SQL注入指令?给出完整过滤器代码
答案:
题目1:JSON输出解析
@Bean public OutputParser<OrderInfo> orderParser() { return new JsonOutputParser<>(OrderInfo.class) .withFallback(raw -> { // 降级策略:提取关键字段 return new OrderInfo(extractField(raw, "orderId")); }); } // 调用 String json = aiClient.generate("生成订单JSON"); OrderInfo order = orderParser().parse(json);题目2:语义相似度缓存
public class SemanticCache { @Cacheable(cacheNames = "ai_responses", key = "#prompt.hashCode()") public String getCachedResponse(String prompt, String currentResponse) { // 计算相似度(Sentence-BERT) float[] currentEmb = model.encode(currentResponse); for (String cached : cache.getAll()) { float[] cachedEmb = model.encode(cached); if (cosineSimilarity(currentEmb, cachedEmb) > 0.95) { return cached; // 返回缓存 } } return currentResponse; } }题目3:提示词过滤
public class PromptSanitizer { private static final Pattern SQL_INJECTION = Pattern.compile( "(?i)\\b(SELECT|UPDATE|DELETE|DROP|UNION|INSERT)\\b" ); public String sanitize(String prompt) { // 过滤SQL关键字 String safe = SQL_INJECTION.matcher(prompt).replaceAll("[REDACTED]"); // 移除特殊字符 return safe.replaceAll("[';\\\\]", ""); } }
📌 今日知识地图
| 模块 | 核心考点 |
|---|---|
| Java基础 | Optional链式调用+时区处理 |
| MySQL | 函数索引+死锁解决方案 |
| Redis/Kafka | 分布式锁续期+消息监控 |
| JVM | G1调优+元空间溢出诊断 |
| 并发 | 线程池动态调整+事务批提交 |
| Spring | 事务失效+安全防护+监控埋点 |
| 大模型 | 输出解析+语义缓存+安全过滤 |
更多推荐

所有评论(0)