当前位置: 首页 > news >正文

Java八股文学习记录之三

1. JUC(Java Util Concurrent)

核心组件

JUC 是java.util.concurrent包的简称,是 Java 并发编程的核心工具包。

锁机制:

  • ReentrantLock:可重入独占锁,支持公平/非公平模式、可中断获取、超时获取。相比 synchronized 更灵活,但需要手动释放锁(try-finally)。

  • ReentrantReadWriteLock:读写锁,读读共享、读写互斥、写写互斥,适合读多写少场景。

  • StampedLock:JDK8 引入,性能更好的读写锁,支持乐观读模式(tryOptimisticRead),乐观读期间允许写操作,读完后需 validate 校验。

同步器(AQS 体系):

  • AQS(AbstractQueuedSynchronizer):JUC 的基石,基于 CLH 队列 + state 变量实现。ReentrantLock、CountDownLatch、Semaphore 等都基于它。

  • CountDownLatch:一次性门闩,一个线程等待 N 个线程完成(await()等待countDown()减到 0),不可复用。

  • CyclicBarrier:循环栅栏,N 个线程互相等待,全部到达后触发屏障动作,可复用。

  • Semaphore:信号量,控制同时访问资源的线程数(限流)。

  • CompletableFuture:异步编排利器,支持链式调用、组合、异常处理。thenApply/thenCompose/thenCombine/allOf/anyOf

并发容器:

  • ConcurrentHashMap:分段锁(JDK7)→ CAS + synchronized(JDK8),红黑树解决哈希冲突,size 用 CounterCell 累加。

  • CopyOnWriteArrayList:写时复制,适合读多写极少场景(如监听器列表),写操作加锁并复制整个数组。

  • BlockingQueue:阻塞队列(ArrayBlockingQueue 有界、LinkedBlockingQueue 可选有界),生产者-消费者模式的基础。

原子类:

  • AtomicIntegerAtomicLongAtomicReference基于 CAS + volatile。

  • LongAdder(JDK8)高并发下比 AtomicLong 性能更好,分散热点到多个 Cell。

线程池:

  • ThreadPoolExecutor 核心参数:corePoolSize、maximumPoolSize、keepAliveTime、workQueue(有界/无界)、RejectedExecutionHandler(四种拒绝策略:AbortPolicy 抛异常、CallerRunsPolicy 调用者执行、DiscardPolicy 静默丢弃、DiscardOldestPolicy 丢弃最旧)。

  • 执行流程:先 corePool → 队列满 → 扩容到 maxPool → 队列再满 → 拒绝策略。

面试常见追问

synchronized 和 ReentrantLock 区别?synchronized 是 JVM 层面的关键字,自动释放锁,非公平;ReentrantLock 是 API 层面,需手动释放,支持公平锁、可中断、超时、条件变量(多个 Condition)。

ConcurrentHashMap 为什么线程安全?JDK8 用 CAS(初始化 table、设置链表头) + synchronized(锁链表/红黑树的头节点) + volatile(Node 的 val 和 next),粒度更细,并发度更高。


2. RAG 检索

概念

RAG(Retrieval-Augmented Generation)是"检索增强生成",核心思路是:大模型在生成回答前,先从外部知识库中检索相关文档,将检索结果作为上下文拼入 prompt,让模型基于检索到的知识来回答,从而减少幻觉、使用最新数据。

流程

用户提问 → 向量化(Embedding) → 向量数据库检索 → 召回 Top-K 相关文档 → 拼入 Prompt → LLM 生成回答

关键技术点

文档处理(Ingestion):

  • 文档切分(Chunking):按字符/段落/语义切分,常用策略有固定大小切分(如 512 token)、递归切分、语义切分。chunk_size 和 overlap 是关键参数。

  • 向量化(Embedding):将文本转为向量。常用模型:text-embedding-3-small、bge-large-zh 等。

  • 存储:向量数据库(Milvus、Pinecone、Weaviate、Pgvector、Elasticsearch 8.x)。

检索优化(核心难点):

  • 混合检索(Hybrid Search):向量检索 + BM25 关键词检索结合,兼顾语义和关键词匹配。

  • 重排序(Re-ranking):召回后用 Cross-encoder 模型重新排序,提升相关性。如 Cohere Rerank、bge-reranker。

  • 查询重写(Query Rewriting):将用户问题改写成更适合检索的形式,如 Multi-Query、HyDE。

  • 多路召回:从不同数据源/不同粒度同时召回,融合排序。

生成增强:

  • 将检索到的文档作为上下文填入 prompt 模板,加上约束("仅根据以上资料回答,不知道就说不知道")。

  • 引用标注:要求模型在回答中标明信息来源。

面试追问

如何评估 RAG 效果?检索指标(Recall@K、MRR、NDCG)+ 生成指标(Faithfulness 忠实度、Answer Relevance 答案相关性、Context Precision)。

chunk 太大或太小有什么问题?太大:检索精度下降,无关内容多,浪费 token。太小:上下文不完整,语义丢失。需要根据文档类型和模型上下文窗口调整。


3. MySQL 索引及其优化

索引基础

索引本质:一种有序的数据结构,帮助快速定位数据,避免全表扫描。类似于书的目录。

常见索引类型(按数据结构):

  • B+Tree 索引(InnoDB 默认):所有数据存在叶子节点,叶子节点形成有序双向链表,非叶子节点只存 key。适合范围查询、排序、等值查询。

  • Hash 索引:只支持等值查询,不支持范围查询和排序,Memory 引擎使用。

  • 全文索引(FULLTEXT):用于文本搜索。

  • 空间索引(R-Tree):地理数据。

按功能分类:

  • 主键索引(聚簇索引):数据行物理存储在叶子节点上。一张表只有一个。

  • 二级索引(非聚簇索引):叶子节点存主键值。查询时需要回表(拿着主键去聚簇索引查完整行数据)。

索引优化策略(高频考点)

1. 最左前缀原则联合索引(a, b, c)相当于创建了(a)(a, b)(a, b, c)三个索引。查询条件必须包含最左列a才能使用索引。WHERE b = 1 AND c = 2不走索引。

2. 覆盖索引查询的列都在索引中,不需要回表,性能最好。EXPLAINExtra: Using index。例如:SELECT a, b FROM t WHERE a = 1在联合索引(a, b)上可直接覆盖。

3. 避免索引失效

  • WHERE条件中对索引列使用函数或表达式:WHERE YEAR(create_time) = 2024→ 应改为WHERE create_time >= '2024-01-01' AND create_time < '2025-01-01'

  • 隐式类型转换:WHERE phone = 13800000000如果 phone 是 varchar,会走全表扫描

  • LIKE '%xxx'左模糊:完全无法使用索引;LIKE 'xxx%'可以

  • OR 连接非索引列可能导致全表扫描

  • !=NOT INIS NULL在部分场景下不走索引

4. 索引设计原则

  • 频繁查询 + WHERE + ORDER BY + GROUP BY 的列适合建索引

  • 区分度高的列放联合索引前面(如 user_id 优于 status)

  • 不要过多索引(影响写入性能)

  • 大表考虑分区表或分库分表

EXPLAIN 解读

字段含义
type访问类型,性能排序:system > const > eq_ref > ref > range > index > ALL
key实际使用的索引
rows预估扫描行数
ExtraUsing index(覆盖索引)、Using filesort(需要额外排序)、Using temporary(临时表,差)

面试追问

为什么用 B+Tree 而不是 B-Tree?B+Tree 只在叶子节点存数据,非叶子节点可以存更多 key,树更矮,IO 次数更少;叶子节点形成有序链表,范围查询效率高。

聚簇索引和非聚簇索引区别?聚簇索引叶子节点直接存数据行;非聚簇索引叶子节点存主键,需要回表。建议主键使用自增 ID,避免随机 UUID 导致页分裂。

大表如何加索引不锁表?MySQL 5.6+ 支持 Online DDL(ALGORITHM=INPLACE),或使用 pt-online-schema-change 工具,通过触发器+影子表的方式无损加索引。


4. LangChain4j 框架和工具调用

概念

LangChain4j是 LangChain 的 Java 版本,用于构建 LLM 应用的框架。核心目标是简化 LLM 集成、RAG、Agent、工具调用等场景。

核心模块

模型集成:

ChatLanguageModel model = OpenAiChatModel.builder() .apiKey("sk-xxx") .modelName("gpt-4") .build(); String answer = model.generate("Hello");

工具调用(Tool Calling / Function Calling):让 LLM 决定调用哪个 Java 方法,根据用户意图自动选择工具并传参。

// 1. 定义工具 @Tool("查询某城市的天气") public String getWeather(@P("城市名称") String city) { return city + ":晴,25°C"; } ​ // 2. 注册工具并对话 Assistant assistant = AiServices.builder(Assistant.class) .chatLanguageModel(model) .tools(new WeatherTool()) .build(); ​ String result = assistant.chat("北京今天天气怎么样?"); // LLM 会自动识别意图 → 调用 getWeather("北京") → 返回结果

RAG 模块:

  • EmbeddingStore:对接向量数据库(Redis、Milvus、Elasticsearch 等)

  • EmbeddingModel:文本向量化

  • DocumentSplitter:文档切分

  • RetrievalAugmentor:统一的 RAG 流程编排

其他关键模块:

  • PromptTemplate:模板化 prompt,支持变量填充

  • ChatMemory:对话记忆管理(MessageWindowChatMemory、TokenWindowChatMemory)

  • AiServices:声明式 AI 服务,接口 + 注解自动代理生成实现

  • Chain:顺序编排多个步骤(如 prompt → LLM → 解析输出)

面试追问

AiServices 的原理?基于动态代理(Proxy),解析接口方法上的注解生成 prompt 模板,调用 LLM,将返回值反序列化为接口返回类型。

工具调用流程是什么样?用户消息 + 工具定义列表 → 发给 LLM → LLM 返回 tool_call 请求(含参数)→ 框架执行对应 Java 方法 → 将结果发回 LLM → LLM 生成最终回答。


5. Skill 编写

概念

Skill(技能)是给 AI Agent 扩展能力的模块化组件。不同平台有不同实现方式,但核心思想一致:将特定领域的知识、工具、流程封装成可复用的技能。

Claude Code 中的 Skill 编写

Skill 是一段 markdown 格式的指令,放在.claude/skills/目录下,通过 frontmatter 定义元数据,正文描述行为。

--- name: my-reviewer description: 按照团队规范审查代码 --- ​ ## 执行步骤 1. 读取所有改动的文件 2. 检查是否遵循命名规范(方法名 camelCase,类名 PascalCase) 3. 检查是否有未处理的异常 4. 检查 SQL 是否有注入风险 5. 输出结构化的审查报告,按严重程度分级

通用 Skill 设计原则

  1. 单一职责:一个 Skill 只做一件事,做好一件事

  2. 清晰的输入/输出:定义好入参格式和返回值格式

  3. 错误处理:异常情况下返回友好信息而非直接抛出

  4. 上下文管理:Skill 要知道自己的边界,不越界做事

  5. 可组合:多个 Skill 可以串行/并行组合完成复杂任务

面试回答思路

核心就是:把一个特定任务的标准操作流程(SOP)固化下来,让 AI 在遇到这类任务时能按既定规范执行,保证输出质量和一致性。关键是要定义清楚触发条件(什么时候用)、执行步骤(怎么做)、输出格式(做成什么样)。


6. 如何写提示词(Prompt Engineering)

核心原则

1. 结构化(最重要)好的 prompt 应该有清晰的结构:

# 角色 你是一个资深的 Java 代码审查专家... ​ # 任务 请审查以下代码,检查潜在的性能问题... ​ # 输入 [粘贴代码] ​ # 输出格式 按严重程度(严重/一般/建议)列出问题,每条包含:位置、问题、建议修复方案 ​ # 约束 - 不要讨论命名风格 - 只关注性能相关的问题

2. 提供示例(Few-Shot)当希望模型输出特定格式时,给 1-2 个示例效果远好于纯文字描述。

3. 设约束 + 分解任务

  • "先分析,再给出结论"

  • "一步步思考(Chain of Thought)"

  • 复杂任务拆成多个子 prompt 依次执行

4. 角色扮演赋予 LLM 一个具体角色能显著提升输出质量。"你是一个有 10 年经验的 Java 架构师" 比直接问效果更好。

常见技巧

技巧说明
零样本(Zero-Shot)直接提问题,不给示例
少样本(Few-Shot)给 1-3 个示例再提问题
思维链(CoT)"让我们一步步思考" 引导模型推理过程
角色扮演设定专业角色限定回答风格
格式约束明确要求 JSON/Markdown/表格 输出
反向提示"在回答前,先列出你可能出错的地方"

面试追问

写 prompt 最常见的问题?

  1. 指令模糊("帮我优化这段代码" 没有说优化什么);2. 信息过载(把所有需求堆在一个 prompt);3. 没有给定输出格式,导致结果不可预测。

System Prompt 和 User Prompt 的区别?System Prompt 设定模型的行为边界和角色(持久性指令),User Prompt 是具体的问题输入。实践中 System Prompt 优先于 User Prompt(模型更倾向于遵守 System Prompt)。


7. Spring 注解

核心注解分类

Bean 定义:

注解说明
@Component通用组件,标记为 Spring Bean
@Service业务逻辑层
@Repository数据访问层(额外翻译持久层异常)
@ControllerWeb 控制器层
@RestController@Controller+@ResponseBody
@Configuration配置类,内部@Bean方法会被代理

依赖注入:

注解说明
@Autowired按类型注入(默认必须,可设 required = false)
@Qualifier配合 @Autowired,按名称指定
@ResourceJSR-250,默认按名称注入
@Value注入配置文件值或 SpEL 表达式

声明周期:

注解说明
@PostConstruct依赖注入完成后执行初始化
@PreDestroyBean 销毁前执行清理
@Scope作用域(singleton/prototype/request/session)

AOP 相关:

注解说明
@Transactional声明式事务(传播行为、隔离级别、回滚策略)
@Aspect定义切面类
@Before/@After/@Around通知类型

条件装配:

注解说明
@ConditionalOnClass类存在时才装配
@ConditionalOnBeanBean 存在时才装配
@ConditionalOnProperty配置值满足条件时才装配
@Profile指定环境才生效

面试追问

@Autowired@Resource的区别?@Autowired 是 Spring 的,默认按类型注入,配合 @Qualifier 按名称;@Resource 是 JSR-250,默认按名称注入,找不到再按类型。

@Transactional失效的场景?

  1. 方法非 public;2. 同类方法调用(this.xxx(),不经过代理);3. 异常被 try-catch 吞掉没抛出来;4. rollbackFor 没配置(默认只回滚 RuntimeException 和 Error);5. 数据库引擎不支持事务(如 MyISAM)。


8. Spring Bean

Bean 生命周期(高频考点)

1. BeanDefinition 注册 ↓ 2. BeanFactoryPostProcessor(可修改 BeanDefinition,如 ${} 占位符替换) ↓ 3. 实例化(反射调用构造器,创建对象实例) ↓ 4. 属性赋值(@Autowired、@Value 等依赖注入) ↓ 5. Aware 接口回调(BeanNameAware → BeanFactoryAware → ApplicationContextAware) ↓ 6. BeanPostProcessor#postProcessBeforeInitialization ↓ 7. @PostConstruct 标注的初始化方法 ↓ 8. InitializingBean#afterPropertiesSet() ↓ 9. init-method(XML 或 @Bean 的 initMethod) ↓ 10. BeanPostProcessor#postProcessAfterInitialization(AOP 代理在此生成) ↓ 11. Bean 就绪,可被使用 ↓ 12. @PreDestroy / DisposableBean#destroy() / destroy-method(容器关闭时销毁)

关键要点

  • BeanPostProcessor是 Spring 的扩展核心,AOP 代理就是在postProcessAfterInitialization中通过 JDK 动态代理或 CGLIB 创建的。

  • 单例和多例的区别:singleton 在容器初始化时就创建完成(急加载);prototype 每次获取时才创建(懒加载),Spring 不管理 prototype Bean 的完整生命周期(不调用销毁方法)。

  • 解决循环依赖:Spring 通过三级缓存解决 singleton 的 setter 注入循环依赖(一级:singletonObjects,完整 bean;二级:earlySingletonObjects,早期引用;三级:singletonFactories,ObjectFactory 可生成代理对象)。构造器注入的循环依赖无法解决,会抛 BeanCurrentlyInCreationException。

Bean 的作用域

作用域说明
singleton默认,IoC 容器中唯一实例
prototype每次获取创建新实例
request每个 HTTP 请求一个实例(Web)
session每个 HTTP Session 一个实例(Web)
application每个 ServletContext 一个实例(Web)

面试追问

为什么构造器注入比字段注入好?

  1. 依赖不可变(final);2. 依赖明确(构造器参数就是所有依赖);3. 方便单元测试(不需要启动 Spring 容器);4. 避免 NPE(编译期确保注入不为 null)。Spring 官方推荐构造器注入。

Spring 如何解决循环依赖?三级缓存机制,核心是用 ObjectFactory 提前暴露"半成品"bean 的引用(刚实例化未注入属性),让另一个 bean 先持有它的引用,等两个 bean 都初始化完后再注入最终版本。只解决单例 setter 注入场景,构造器注入循环无法解决。


9. 如何 SQL 防止事务冲突

事务并发问题

问题描述
脏读读到了另一个事务未提交的修改
不可重复读同一事务内两次读取同一行,结果不同(被别的事务 update 了)
幻读同一事务内两次范围查询,结果集条数不同(被别的事务 insert 了)
丢失更新两个事务同时读再先后更新,后提交的覆盖了先提交的

解决方案

1. 隔离级别(Isolation Level)

级别脏读不可重复读幻读并发性能
READ UNCOMMITTED可能可能可能最高
READ COMMITTED避免可能可能
REPEATABLE READ(MySQL 默认)避免避免部分避免
SERIALIZABLE避免避免避免

2. 乐观锁(推荐用于读多写少)

-- 版本号机制 UPDATE order SET amount = 100, version = version + 1 WHERE id = 1 AND version = 5; -- 如果 version 变了,受影响行数为 0 ​ -- 或使用时间戳 UPDATE product SET stock = 10, update_time = NOW() WHERE id = 1 AND update_time = '2024-01-01 12:00:00';

在应用层检查受影响行数,为 0 则重试或抛异常。

3. 悲观锁(适合冲突概率高的场景)

-- SELECT ... FOR UPDATE:行锁,其他事务的 SELECT FOR UPDATE 会等待 -- 必须在事务中使用,提交/回滚后释放锁 BEGIN; SELECT stock FROM product WHERE id = 1 FOR UPDATE; UPDATE product SET stock = stock - 1 WHERE id = 1; COMMIT;

4. 分布式锁(跨服务场景)使用 Redis(SETNX + 过期时间 + Redisson)+ Lua 脚本保证原子性,或 Zookeeper 临时顺序节点。

5. 其他策略

  • 幂等设计:通过唯一索引(如订单号的唯一约束)防止重复插入

  • CAS 更新UPDATE ... WHERE field = old_value,发现值被改过则放弃

  • 串行化:将对同一资源的操作排队(如 MQ 单线程消费)

  • 分段锁:将库存分散到多个 slot,减少竞争热点(如stock_0,stock_1, ...,stock_9

实战建议

  • 能通过 SQL 原子操作完成的,不要用"读-判断-写"模式(如直接UPDATE ... SET count = count - 1 WHERE count > 0

  • 乐观锁适合读多写少、冲突率低的场景(如用户资料修改)

  • 悲观锁适合冲突率高的场景(如秒杀扣库存),但要注意死锁风险

  • 一定要监控事务时长,长事务会导致锁持有时间长、阻塞其他请求

面试追问

MySQL InnoDB RR 隔离级别如何解决幻读?通过 Gap Lock(间隙锁)+ Record Lock(记录锁)= Next-Key Lock,锁定一个区间,防止其他事务在这个区间内 INSERT。但不完全解决(如当前读才能加 gap lock,快照读不会)。MVCC 机制通过 Read View 在快照读下避免了幻读。


10. 如何总结项目的优点亮点

回答框架:STAR + 量化

STAR 法则:

  • S(Situation):项目背景、面临的问题

  • T(Task):你承担的任务/角色

  • A(Action):你采取了什么行动(技术选型、方案设计、关键决策)

  • R(Result):取得了什么结果(必须量化

提炼亮点的维度

维度示例
性能提升"接口响应时间从 2s 降低到 200ms"
技术难度"自研分库分表中间件,支持动态扩容"
业务影响"支撑日均 1000 万笔订单处理"
成本降低"通过 SQL 优化减少数据库 CPU 30%,省了两台服务器"
工程质量"引入自动化测试,上线回归时间从 4 小时缩到 30 分钟"
故障处理"定位并修复了一个死锁问题,避免了线上延迟连续飙升"

典型回答模板

"我负责重构了订单查询模块。原有接口在高并发下响应时间超过 2 秒,我通过分析慢查询日志发现是索引缺失和多表关联导致。我做了三层优化:第一,补充联合索引将查询从全表扫描优化为 ref 级别;第二,引入 CQRS 模式,将读写分离,查询走 ES 实现毫秒级搜索;第三,对热点数据加 Caffeine 本地缓存 + Redis 二级缓存。最终接口 P99 从 2s 降到 150ms,QPS 从 500 提升到 5000,缓存命中率达到 95%。"

常见错误

  1. 只讲功能,不讲价值:不要说"我做了个 CRUD 页面",要说"我实现的后台管理系统支撑了 50 个运营人员的日常工作"。

  2. 全是团队功劳:用"我"主导/负责/设计,而不是"我们"。

  3. 没有数据支撑:用具体数字替代模糊形容词("快了很多" → "响应时间降低了 70%")。

  4. 技术堆砌不用说原理:说了用 Redis,要说为什么用、怎么用的、解决了什么问题。

  5. 没有困难=没有亮点:主动提及遇到的难题和你如何解决的,这是最好的加分项。

http://www.jsqmd.com/news/919754/

相关文章:

  • 2026年永康废旧回收靠谱机构技术维度TOP5盘点 - 优质品牌商家
  • 大语言模型量化技术:双极INT格式与比特级矩阵乘法优化
  • AI科技热点日报 | 2026年5月30日
  • 如何用ImageGlass打造你的Windows终极图像浏览器:90+格式支持与深度体验指南
  • 2026年学C语言容易找到工作吗?普通人学习还有没有作用
  • Claude Code 从零到上手指南:国产工具链复现80% Agent能力,DeepSeek+LangChain实战
  • 基于小程序的大学生竞赛管理系统毕设
  • 2026年5月新消息:探寻性价比高的汽车开关销售公司哪家强 - 2026年企业资讯
  • Qwen2.5-7B大语言模型:解密70亿参数智能大脑的模块化设计哲学 [特殊字符]
  • Unity材质球大合集
  • 3个核心特性揭秘:Scarab如何重塑空洞骑士模组管理体验
  • 2026年福建企业管理咨询服务推荐榜:精益生产、数字化转型与体系认证深度横评 - 精选优质企业推荐官
  • 从入门到精通:PyBaMM电池建模实战指南与性能优化技巧
  • 基于Dify+EdgeOne的化学试剂反应在线展示系统
  • 自动跑,不需要点击 allow
  • 2026成都到喀什物流专线评测:成都靠谱物流公司/易碎品木箱打包服务/物流货物木架加固打包/4家品牌核心维度对比 - 优质品牌商家
  • 2026成都机械设备跨省运输品牌实测与技术解析 - 优质品牌商家
  • 怎么实现截图功能?Edge浏览器插件实现高清区域截图的核心关键点
  • 如何用Python实现QQ空间历史数据完整备份:GetQzonehistory深度解析与实践指南
  • 2026宜宾门窗品牌选型:乐山哪家门窗好看/乐山哪里有门窗厂/乐山定制门窗/技术维度拆解与靠谱参考 - 优质品牌商家
  • Android FBE密钥存储与生命周期全解析
  • 告别网盘限速:九大主流网盘直链下载助手使用全攻略
  • 2026年Q2山东出国工作市场深度解析:如何选择可靠的服务合作伙伴 - 2026年企业资讯
  • 子图同构问题的表格化并行解法Δ-Motif解析
  • 宜宾门窗厂技术实力盘点:核心维度与靠谱品牌解析 - 优质品牌商家
  • 客观复盘贾子(Kucius)AI二十项不可修复原罪理论:从初始评价、多层误解修正到内核本质完整研判
  • LangChain 完全入门指南:从零搭建大模型应用
  • 2026年福建企业管理咨询与精益生产服务商深度横评推荐 - 精选优质企业推荐官
  • 小白零基础秒懂:大模型Harness是什么?补齐AI干活的最后一块短板
  • 位掩码的一些tip