diff --git a/.gitignore b/.gitignore
index 815e8cc827..c2c269f735 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,8 +6,6 @@ package-lock.json
dump.rdb
docs/.vuepress/.cache/
docs/.vuepress/.temp/
-docs/dist/
-dist.zip
images
*.log
.yarn
diff --git a/README.md b/README.md
index c84b4eb65c..a00f3e8f85 100644
--- a/README.md
+++ b/README.md
@@ -44,7 +44,7 @@

-一个人可以走得很快,但一群人才能走得更远。[二哥的编程星球](https://javabetter.cn/zhishixingqiu/)已经有 **10000 多名** 球友加入了(马上涨价到 169 元,抓紧时间趁没涨价前加入吧),如果你也需要一个优质的学习环境,扫描下方的优惠券加入我们吧。
+一个人可以走得很快,但一群人才能走得更远。[二哥的编程星球](https://javabetter.cn/zhishixingqiu/)已经有 **9000 多名** 球友加入了(戳[链接](https://javabetter.cn/zhishixingqiu/)了解详情),如果你也需要一个良好的学习环境,扫描下方的优惠券加入我们吧。新人可免费体验 3 天,不满意可全额退款(只能帮你到这里了😄)。
@@ -54,13 +54,11 @@
-新人可免费体验 3 天,不满意可全额退款(只能帮你到这里了😄)。
-这是一个 **简历精修 + 编程项目实战 + Java 面试指南 + LeetCode 刷题**的私密圈子,你可以阅读星球专栏、向二哥提问、帮你制定学习计划、和球友一起打卡成长。两个置顶帖「球友必看」和「知识图谱」里已经沉淀了非常多优质的内容,**相信能帮助你走的更快、更稳、更远**。
+这是一个**编程学习指南 + Java 项目实战 + LeetCode 刷题+简历精修**的私密圈子,你可以阅读星球专栏、向二哥提问、帮你制定学习计划、和球友一起打卡成长。两个置顶帖「球友必看」和「知识图谱」里已经沉淀了非常多优质的内容,**相信能帮助你走的更快、更稳、更远**。
- [二哥精修简历服务,让你投了就有笔试&面试✌️](https://javabetter.cn/zhishixingqiu/jianli.html)
- [二哥的RAG知识库项目派聪明上线了,AI时代你必须拥有的实战项目✌️](https://javabetter.cn/zhishixingqiu/paismart.html)
-- [Go 版本的派聪明RAG知识库项目上线了,学习 Go 语言的小伙伴有福了✌️](https://javabetter.cn/zhishixingqiu/paismart-go.html)
- [二哥的技术派实战项目更新了,秋招&暑期/日常实习大杀器✌️](https://javabetter.cn/zhishixingqiu/paicoding.html)
- [二哥的PmHub微服务实战项目上线了,校招和社招均可用✌️](https://javabetter.cn/zhishixingqiu/paicoding.html)
- [二哥的Java面试指南专栏更新了,求职面试必备✌️](https://javabetter.cn/zhishixingqiu/mianshi.html)
@@ -573,9 +571,6 @@

-如果想部署服务器,可以执行 `pnpm docs:build` 打包生成 dist 目录,里面就是静态资源文件了。
-
-执行 `zip -r dist.zip dist` 压缩为 dist.zip 包,然后上传到服务器的 Nginx 对应的静态资源目录下。再执行 `unzip dist.zip` 解压即可。
# 联系作者
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 0000000000..411fb0d34b
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,5 @@
+
+node_modules/
+src/.vuepress/.cache/
+src/.vuepress/.temp/
+src/.vuepress/dist/
diff --git a/docs/src/.vuepress/sidebar.ts b/docs/src/.vuepress/sidebar.ts
index 3868568ae2..2e7f743cbc 100644
--- a/docs/src/.vuepress/sidebar.ts
+++ b/docs/src/.vuepress/sidebar.ts
@@ -5,7 +5,6 @@ export default sidebar({
"readme.md",
"jianli",
"paismart",
- "paismart-go",
"paicoding",
"pmhub",
"mianshi",
diff --git a/docs/src/.vuepress/theme.ts b/docs/src/.vuepress/theme.ts
index c272586648..0370473217 100644
--- a/docs/src/.vuepress/theme.ts
+++ b/docs/src/.vuepress/theme.ts
@@ -184,9 +184,9 @@ export default hopeTheme({
notice: [
{
- match: /^(?!\/zhishixingqiu\/).*$/,
+ path: "/",
title: "二哥的编程星球",
- content: "这是一个简历精修 + 编程项目实战 + Java 面试指南 + LeetCode 刷题的私密圈子,已经有 10000+ 名球友加入(即将涨价至 169 元)",
+ content: "这是一个Java面试指南 + 编程项目实战 + 简历精修 + LeetCode 刷题的私密圈子,已有 9000 名球友加入",
actions: [
{
text: "这就去加入",
@@ -247,7 +247,6 @@ export default hopeTheme({
// 如果你需要 PWA。安装 @vuepress/plugin-pwa 并取消下方注释
pwa: {
- update: "hint",
favicon: "https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/favicon.ico",
cacheHTML: true,
cacheImage: true,
diff --git a/docs/src/home.md b/docs/src/home.md
index e81c2def18..567d064138 100644
--- a/docs/src/home.md
+++ b/docs/src/home.md
@@ -53,7 +53,7 @@ head:

-一个人可以走得很快,但一群人才能走得更远。[二哥的编程星球](https://javabetter.cn/zhishixingqiu/)已经有 **10000 多名** 球友加入了(马上要涨价到 169 元,抓紧时间趁没涨价前加入吧),如果你也需要一个优质的学习环境,扫描下方的优惠券加入我们吧。
+一个人可以走得很快,但一群人才能走得更远。[二哥的编程星球](https://javabetter.cn/zhishixingqiu/)已经有 **9000 多名** 球友加入了(戳[链接](https://javabetter.cn/zhishixingqiu/)了解详情),如果你也需要一个良好的学习环境,扫描下方的优惠券加入我们吧。新人可免费体验 3 天,不满意可全额退款(只能帮你到这里了😄)。
@@ -63,13 +63,11 @@ head:
-新人可免费体验 3 天,不满意可全额退款(只能帮你到这里了😄)。
-这是一个 **简历精修 + 编程项目实战 + Java 面试指南 + LeetCode 刷题**的私密圈子,你可以阅读星球专栏、向二哥提问、帮你制定学习计划、和球友一起打卡成长。两个置顶帖「球友必看」和「知识图谱」里已经沉淀了非常多优质的内容,**相信能帮助你走的更快、更稳、更远**。
+这是一个**编程学习指南 + Java 项目实战 + LeetCode 刷题的私密圈子**,你可以阅读星球专栏、向二哥提问、帮你制定学习计划、和球友一起打卡成长。两个置顶帖「球友必看」和「知识图谱」里已经沉淀了非常多优质的内容,**相信能帮助你走的更快、更稳、更远**。
- [二哥精修简历服务,让你投了就有笔试&面试✌️](https://javabetter.cn/zhishixingqiu/jianli.html)
- [二哥的RAG知识库项目派聪明上线了,AI时代你必须拥有的实战项目✌️](https://javabetter.cn/zhishixingqiu/paismart.html)
-- [Go 版本的派聪明RAG知识库项目上线了,学习 Go 语言的小伙伴有福了✌️](https://javabetter.cn/zhishixingqiu/paismart-go.html)
- [二哥的技术派实战项目更新了,秋招&暑期/日常实习大杀器✌️](https://javabetter.cn/zhishixingqiu/paicoding.html)
- [二哥的PmHub微服务实战项目上线了,校招和社招均可用✌️](https://javabetter.cn/zhishixingqiu/paicoding.html)
- [二哥的Java面试指南专栏更新了,求职面试必备✌️](https://javabetter.cn/zhishixingqiu/mianshi.html)
diff --git a/docs/src/sidebar/sanfene/collection.md b/docs/src/sidebar/sanfene/collection.md
index da3a654be8..be0f3faa2d 100644
--- a/docs/src/sidebar/sanfene/collection.md
+++ b/docs/src/sidebar/sanfene/collection.md
@@ -96,11 +96,11 @@ head:
Java 中的队列主要通过 Queue 接口和并发包下的 BlockingQueue 两个接口来实现。
-优先级队列 PriorityQueue 是一个无界队列,它的元素按照自然顺序排序或者 Comparator 比较器进行排序。
+优先级队列 PriorityQueue 实现了 Queue 接口,是一个无界队列,它的元素按照自然顺序排序或者 Comparator 比较器进行排序。

-双端队列 ArrayDeque 是一个基于数组的,可以在两端插入和删除元素的队列。
+双端队列 ArrayDeque 也实现了 Queue 接口,是一个基于数组的,可以在两端插入和删除元素的队列。

@@ -122,11 +122,11 @@ LinkedList 实现了 Queue 接口的子类 Deque,所以也可以当做双端
#### 队列和栈的区别了解吗?
-队列是一种先进先出(FIFO, First-In-First-Out)的数据结构,第一个加入队列的元素会成为第一个被移除的元素,适用于需要按顺序处理任务的场景,比如消息队列、任务调度等。
+队列是一种先进先出(FIFO, First-In-First-Out)的数据结构,第一个加入队列的元素会成为第一个被移除的元素。

-栈是一种后进先出(LIFO, Last-In-First-Out)的数据结构,最后一个加入栈的元素会成为第一个被移除的元素,适用于需要回溯的场景,比如函数调用栈、浏览器历史记录等。
+栈是一种后进先出(LIFO, Last-In-First-Out)的数据结构,最后一个加入栈的元素会成为第一个被移除的元素。

@@ -215,9 +215,9 @@ ArrayList 适用于:
LinkedList 适用于:
-- 在列表中间频繁插入和删除元素的场景。
-- 顺序访问多于随机访问的场景。
-- LinkedList 可以实现队列(FIFO)和栈(LIFO)。
+- 频繁插入和删除:在列表中间频繁插入和删除元素的场景。
+- 不需要快速随机访问:顺序访问多于随机访问的场景。
+- 队列和栈:由于其双向链表的特性,LinkedList 可以实现队列(FIFO)和栈(LIFO)。
#### 链表和数组有什么区别?
@@ -233,10 +233,6 @@ LinkedList 适用于:
> 5. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的快手同学 2 一面面试原题:ArrayList和LinkedList区别
> 6. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的得物面经同学 9 面试题目原题:集合里面的arraylist和linkedlist的区别是什么?有何优缺点?
-memo:2025 年 9 月 07 日修改至此,[今天在帮球友修改简历时](https://javabetter.cn/zhishixingqiu/jianli.html),收到反馈说,蚂蚁集团转正了。希望看到这里的你也能顺利通过面试,拿到心仪的 offer。
-
-
-
### 3.ArrayList 的扩容机制了解吗?
了解。当往 ArrayList 中添加元素时,会先检查是否需要扩容,如果当前容量+1 超过数组长度,就会进行扩容。
@@ -391,15 +387,6 @@ HashMap 的初始容量是 16,随着元素的不断添加,HashMap 就需要
扩容后的数组大小是原来的 2 倍,然后把原来的元素重新计算哈希值,放到新的数组中。
-#### 负载因子干什么用的?
-
-负载因子(load factor)是一个介于 0 和 1 之间的数值,用于衡量哈希表的填充程度。它表示哈希表中已存储的元素数量与哈希表容量之间的比例。
-
-- 负载因子过高(接近 1)会导致哈希冲突增加,影响查找、插入和删除操作的效率。
-- 负载因子过低(接近 0)会浪费内存,因为哈希表中有大量未使用的空间。
-
-默认的负载因子是 0.75,这个值在时间和空间效率之间提供了一个良好的平衡。
-
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的小米 25 届日常实习一面原题:讲一讲 HashMap 的原理
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的华为一面原题:说下 Java 容器和 HashMap
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的华为一面原题:说下 Redis 和 HashMap 的区别
@@ -410,10 +397,6 @@ HashMap 的初始容量是 16,随着元素的不断添加,HashMap 就需要
> 8. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的百度面经同学 1 文心一言 25 实习 Java 后端面试原题:hashmap 的底层实现原理、put()方法实现流程、扩容机制?
> 9. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯面经同学 27 云后台技术一面面试原题:Hashmap的底层?为什么链表要变成红黑树?为什么不用平衡二叉树?
-memo:2025 年 9 月 24 日修改至此。今天[有球友发私信](https://javabetter.cn/zhishixingqiu/)口碑了面渣逆袭,说老有用了,他最近拿到了招银网络科技的 offer。
-
-
-
### 9.你对红黑树了解多少?
红黑树是一种自平衡的二叉查找树:
@@ -852,21 +835,15 @@ if (e.hash == hash &&
树化发生在 table 数组的长度大于 64,且链表的长度大于 8 的时候。
-#### 为什么是 8 呢?
-
-
-
-和统计学有关。理想情况下,使用随机哈希码,链表里的节点符合泊松分布,出现节点个数的概率是递减的,节点个数为 8 的情况,发生概率仅为 `0.00000006`。
+为什么是 8 呢?源码的注释也给出了答案。
-也就是说,在正常情况下,链表长度达到 8 是个小概率事件。
+
-8 是一个平衡点。当链表长度小于 8 时,即使是 O(n) 的查找,由于 n 比较小,实际性能还是可以接受的,而且链表的内存开销小。当链表长度达到 8 时,查找性能已经比较差了,这时候转换为红黑树的收益就比较明显了,因为红黑树的查找、插入、删除操作的时间复杂度都是 O(log n)。
+红黑树节点的大小大概是普通节点大小的两倍,所以转红黑树,牺牲了空间换时间,更多的是一种兜底的策略,保证极端情况下的查找效率。
-> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的京东面经同学 19 JDS后端技术一面面试原题:HashMap 链表转红黑树阈值
+阈值为什么要选 8 呢?和统计学有关。理想情况下,使用随机哈希码,链表里的节点符合泊松分布,出现节点个数的概率是递减的,节点个数为 8 的情况,发生概率仅为`0.00000006`。
-memo:2025 年 8 月 9 日修改到此。 今天有读者反馈,最近在[看面渣逆袭](https://javabetter.cn/sidebar/sanfene/nixi.html),面试中碰见的概率非常高,好多别的八股没有提到的你总结的都有。能收到这样的正反馈,对我真的很重要,感谢。
-
-
+至于红黑树转回链表的阈值为什么是 6,而不是 8?是因为如果这个阈值也设置成 8,假如发生碰撞,节点增减刚好在 8 附近,会发生链表和红黑树的不断转换,导致资源浪费。
### 20.HashMap扩容发生在什么时候呢?
@@ -1034,10 +1011,6 @@ if (hiHead != null)
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的奇安信面经同学 1 Java 技术一面面试原题:map 集合在使用时候一般都需要写容量值?为什么要写?扩容机制?
> 4. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的百度面经同学 1 文心一言 25 实习 Java 后端面试原题:hashmap 的底层实现原理、put()方法实现流程、扩容机制?
-memo:2025 年 8 月 9 日修改到此。今天在[帮球友修改简历](https://javabetter.cn/zhishixingqiu/jianli.html)的时候,收到这样一个反馈:很感谢二哥让我至少暑期上岸了,目前在荣耀。感谢球友们每一次的口碑。
-
-
-
### 22.JDK 8 对 HashMap 做了哪些优化呢?
①、底层数据结构由数组 + 链表改成了数组 + 链表或红黑树的结构。
diff --git a/docs/src/sidebar/sanfene/fenbushi.md b/docs/src/sidebar/sanfene/fenbushi.md
index b16cf3e258..f3cb3ce8aa 100644
--- a/docs/src/sidebar/sanfene/fenbushi.md
+++ b/docs/src/sidebar/sanfene/fenbushi.md
@@ -2,7 +2,6 @@
title: 分布式面试题,12道分布式八股文(8千字25张手绘图),面渣逆袭必看👍
shortTitle: 面渣逆袭-分布式
author: 三分恶
-date: 2025-09-23
category:
- 面渣逆袭
tag:
@@ -18,43 +17,19 @@ head:
## 分布式理论
-### 1. 说说 CAP 原则?
+### 1\. 说说 CAP 原则?
-CAP 是分布式系统设计中的一个非常重要的定理,它指出分布式系统不可能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三个特性,最多只能同时满足其中两个。
+CAP 原则又称 CAP 定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性)这 3 个基本需求,最多只能同时满足其中的 2 个。
-
+
-一致性指的是所有节点在同一时间看到的数据都是一致的。比如我在北京的服务器上更新了用户的余额,那么上海的服务器上也应该立即看到这个更新后的余额。强一致性要求数据更新完成后,任何后续的访问都能返回更新后的值。
+| 选项 | 描述 |
+| --------------------------------- | -------------------------------------------------------------------------------------------------------------- |
+| Consistency(一致性) | 指数据在多个副本之间能够保持一致的特性(严格的一致性) |
+| Availability(可用性) | 指系统提供的服务必须一直处于可用的状态,每次请求都能获取到非错的响应(不保证获取的数据为最新数据) |
+| Partition tolerance(分区容错性) | 分布式系统在遇到任何网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务,除非整个网络环境都发生了故障 |
-可用性是指系统在正常响应时间内返回合理的响应,即使部分节点出现故障,系统仍然可以继续提供服务。比如电商网站不能因为某个数据库节点挂了就完全无法访问,用户至少应该能看到商品信息,可能只是下单功能暂时不可用。
-
-分区容错性是指当网络分区故障发生时,系统仍然能够继续运行。网络分区是分布式系统中不可避免的问题,比如机房之间的网络中断,这时候不同机房的节点就无法正常通信了。
-
-#### 谈一下最终一致性和强一致性个人的理解
-
-强一致性要求任何时候所有节点看到的数据都是完全相同的。也就是数据一旦写入成功,系统中所有的读操作都必须能立即读到最新的值。
-
-
-
-就像银行转账一样,钱从 A 账户扣除的同时必须立即加到 B 账户上,不能存在中间状态。
-
-也就是说,涉及到金额计算的,必须保证强一致性。比如用户充值,扣款成功就必须立即反映到用户余额上,而且所有的服务节点都要能看到最新的余额。
-
-强一致性的代价是比较高的。为了保证所有节点的数据同步,系统需要在写操作时等待所有相关节点都确认更新完成,这会带来较高的延迟。而且在网络分区或节点故障时,系统可能会选择暂停服务来保证一致性,可用性会受到影响。
-
-最终一致性相对比较宽松,它允许系统在短时间内存在数据不一致的情况,但保证经过一段时间后,所有节点的数据最终会达到一致的状态。
-
-
-
-最终一致性的典型应用就是分布式缓存系统。比如 Redis 集群中,主节点写入成功后立即返回,然后异步复制到从节点。这种模式下,读操作可能会读到稍微过期的数据,但系统的整体性能和可用性都很好。
-
->1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的网易同学 4 云音乐后端技术面试原题:介绍一下CAP理论,谈一下最终一致性和强一致性个人的理解
-
-memo:2025 年 9 月 23 日修改至此,今天[帮球友修改简历](https://javabetter.cn/zhishixingqiu/jianli.html)的时候,收到一位球友的反馈说,非常感谢二哥编程星球这个平台,让他有机会再这里学习教程、项目,以及和广大球友交流,这对于他的成长有很大帮助。这种正反馈对我真的太重要了,感谢。
-
-
-
-### 2. 为什么 CAP 不可兼得呢?
+### 2\. 为什么 CAP 不可兼得呢?
首先对于分布式系统,分区是必然存在的,所谓分区指的是分布式系统可能出现的字区域网络不通,成为孤立区域的的情况。
diff --git a/docs/src/sidebar/sanfene/javase.md b/docs/src/sidebar/sanfene/javase.md
index 129236a607..584ab6d470 100644
--- a/docs/src/sidebar/sanfene/javase.md
+++ b/docs/src/sidebar/sanfene/javase.md
@@ -2,7 +2,7 @@
title: Java面试题之Java基础篇,56道Java基础八股文(2.3万字68张手绘图),面渣逆袭必看👍
shortTitle: 面渣逆袭-Java SE
author: 三分恶&沉默王二
-date: 2025-09-19
+date: 2025-06-14
category:
- 面渣逆袭
tag:
@@ -246,12 +246,6 @@ System.out.println("Integer.MIN_VALUE in binary: " + Integer.toBinaryString(Inte
> 4. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的用友面试原题:说说 8 大数据类型?
> 5. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的快手同学 2 一面面试原题:给Integer最大值+1,是什么结果
-memo:2025 年 8 月 23 日修改至此。 今天在修改简历的时候碰到这样一个反馈,一位球友蚂蚁已经转正了,但为了防患于未然,打算再冲一段秋招,黑马点评已经换成了[派聪明 RAG](https://javabetter.cn/zhishixingqiu/paismart.html),简历的写法直接照搬了例子,很好很新项目,直接用了。
-
->派聪明简历写法:[https://paicoding.com/column/10/2](https://paicoding.com/column/10/2)
-
-
-
### 8.自动类型转换、强制类型转换了解吗?
推荐阅读:[聊聊基本数据类型的转换](https://javabetter.cn/basic-grammar/type-cast.html)
@@ -391,7 +385,7 @@ int autoAdd(int count)
推荐阅读:[计算机系统基础(四)浮点数](http://kaito-kidd.com/2018/08/08/computer-system-float-point/)
-float 表示小数的方式是基于 IEEE 754 标准的,采用二进制浮点数格式。
+`float`类型的小数在计算机中是通过 IEEE 754 标准的单精度浮点数格式来表示的。
$$
V = (-1)^S \times M \times 2^E
@@ -408,7 +402,9 @@ $$

-1 位符号位、8 位指数位、23 位尾数位。符号位决定正负,0 表示正数,1 表示负数。指数位存储的是偏置后的指数,实际指数要减去 127。尾数位存储的是小数部分的二进制表示。
+1. **符号位(Sign bit)**:1 位
+2. **指数部分(Exponent)**:10 位
+3. **尾数部分(Mantissa,或 Fraction)**:21 位
按照这个规则,将十进制数 25.125 转换为浮点数,转换过程是这样的:
@@ -426,10 +422,6 @@ $$
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的帆软同学 3 Java 后端一面的原题:float 是怎么表示小数的
-memo:2025 年 08 月 23 日更新至此。[星球里其实来了](https://javabetter.cn/zhishixingqiu/)蛮多海外读书的同学,能帮助到大家我真的非常开心。
-
-
-
### 16.讲一下数据准确性高是怎么保证的?(补充)
> 2024 年 04 月 21 日增补
@@ -746,13 +738,13 @@ class Wanger {
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团面经同学 16 暑期实习一面面试原题:请说说多态、重载和重写
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动面经同学19番茄小说一面面试原题:多态的用法,多态的实现原理
-### 20.🌟重载和重写的区别?
+### 20.重载和重写的区别?
推荐阅读:[方法重写 Override 和方法重载 Overload 有什么区别?](https://javabetter.cn/basic-extra-meal/override-overload.html)
-如果一个类有多个名字相同但参数个数不同的方法,我们通常称这些方法为方法重载。
+如果一个类有多个名字相同但参数个数不同的方法,我们通常称这些方法为方法重载(overload)。如果方法的功能是一样的,但参数不同,使用相同的名字可以提高程序的可读性。
-如果子类具有和父类一样的方法(参数相同、返回类型相同、方法名相同,但方法体不同),我们称之为方法重写。
+如果子类具有和父类一样的方法(参数相同、返回类型相同、方法名相同,但方法体可能不同),我们称之为方法重写(override)。方法重写用于提供父类已经声明的方法的特殊实现,是实现多态的基础条件。

@@ -861,11 +853,6 @@ class ShapeDrawer {
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的帆软同学 3 Java 后端一面的原题:设计方法,李氏原则,还了解哪些设计原则
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团面经同学 16 暑期实习一面面试原题:请说说多态、重载和重写
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的招银网络科技面经同学 9 Java 后端技术一面面试原题:Java设计模式中的开闭原则,里氏替换了解嘛
-> 4. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的中小厂面经同学6 广州中厂面试原题:重写和重载
-
-memo:2025 年 9 月 24 日修改至此,今天[有球友发私信](https://javabetter.cn/zhishixingqiu/)说拿到了招银网络科技的 offer,问还能不能谈薪,总包还可以,但讲真银行谈薪的空间真不大,😄
-
-
### 21.访问修饰符 public、private、protected、以及默认时的区别?
@@ -2243,28 +2230,10 @@ Java IO 流的划分可以根据多个维度进行,包括数据流的方向(
#### IO 流用到了什么设计模式?
-用到了——**装饰器模式**,装饰器模式的核心思想是在不改变原有对象结构的前提下,动态地给对象添加新的功能。
+其实,Java 的 IO 流体系还用到了一个设计模式——**装饰器模式**。

-具体到 Java IO 中,InputStream 和 OutputStream 这些抽象类定义了基本的读写操作,然后通过各种装饰器类来增强功能。比如 BufferedInputStream 给基础的输入流增加了缓冲功能,DataInputStream 增加了读取基本数据类型的能力,它们都是对基础流的装饰和增强。
-
-```java
-InputStream input = new BufferedInputStream(
- new DataInputStream(
- new FileInputStream("data.txt")
- )
-);
-```
-
-这里 FileInputStream 提供基本的文件读取能力,DataInputStream 装饰它增加了数据类型转换功能,BufferedInputStream 再装饰它增加了缓冲功能。每一层装饰都在原有功能基础上增加新特性,而且可以灵活组合。
-
-我对装饰器模式的理解是它很好地体现了“组合优于继承”的设计原则。优势在于运行时动态组合功能,而且遵循开闭原则,可以在不修改现有代码的情况下增加新功能。
-
-memo:2025 年 9 月 19 日修改至此,今天[有球友在 VIP 群里](https://javabetter.cn/zhishixingqiu/)报喜说上岸美团了,恭喜他!9 月份正是一个收获的季节,大家都要加油哦。
-
-
-
#### Java 缓冲区溢出,如何预防
Java 缓冲区溢出主要是由于向缓冲区写入的数据超过其能够存储的数据量。可以采用这些措施来避免:
@@ -2738,7 +2707,7 @@ Person 类的信息在编译时就确定了,那假如在编译期无法确定

-比如说我们可以动态加载类并创建对象:
+比如说我们可以装来动态加载类并创建对象:
```java
String className = "java.util.Date";
@@ -2774,7 +2743,7 @@ Class> clazz = Class.forName("com.example.MyClass");
Object instance = clazz.newInstance();
```
-②、Java 的动态代理机制就使用了反射来创建代理类。代理类可以在运行时动态处理方法调用,这在实现 AOP 和拦截器时非常有用。
+②、Java 的动态代理(Dynamic Proxy)机制就使用了反射来创建代理类。代理类可以在运行时动态处理方法调用,这在实现 AOP 和拦截器时非常有用。
```java
InvocationHandler handler = new MyInvocationHandler();
@@ -2792,24 +2761,9 @@ Method testMethod = testClass.getMethod("testSomething");
testMethod.invoke(testInstance);
```
-④、最常见的是写通用的工具类,比如对象拷贝工具。比如说 BeanUtils、MapStruct 等等,能够自动拷贝两个对象之间的同名属性,就是通过反射来实现的。
-
-
-
-
#### 反射的原理是什么?
-每个类在加载到 JVM 后,都会在方法区生成一个对应的 Class 对象,这个对象包含了类的所有元信息,比如字段、方法、构造器、注解等。
-
-通过这个 Class 对象,我们就能在运行时动态地创建对象、调用方法、访问字段。
-
-### 反射的优缺点是什么?
-
-反射的优点还是很明显的。首先是能够在运行时动态操作类和对象。其次是能够编写通用的代码,一套代码可以处理不同类型的对象。还有就是能够突破访问限制,访问 private 字段和方法,这在反编译场景下很有用。
-
-但反射的缺点也不少。最明显的是性能问题,反射操作比直接调用要慢很多,因为需要在运行时解析类信息、进行类型检查、权限验证等。
-
-其次是反射能够绕过访问控制,访问和修改 private 成员,这会破坏类的封装。
+Java 程序的执行分为编译和运行两步,编译之后会生成字节码(.class)文件,JVM 进行类加载的时候,会加载字节码文件,将类型相关的所有信息加载进方法区,反射就是去获取这些信息,然后进行各种操作。
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团面经同学 2 Java 后端技术一面面试原题:Java 反射用过吗?
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团面经同学 18 成都到家面试原题:反射及其应用场景
@@ -2817,10 +2771,6 @@ testMethod.invoke(testInstance);
> 4. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团面经同学 3 Java 后端技术一面面试原题:java 的反射机制,反射的应用场景 AOP 的实现原理是什么,与动态代理和反射有什么区别
> 5. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的比亚迪面经同学 12 Java 技术面试原题:java的反射
-memo:2025 年 9 月 27 日修改至此,今天[在帮球友修改简历](https://javabetter.cn/zhishixingqiu/)的时候,碰到这样一个反馈,很感动:两个月前在特别焦虑迷茫时找过一次二哥,你说了别担心先去做先去投之类的话那次沟通后让我清醒了很多,我开始停止设想坏的结果,照着简历学习八股,投简历,最后收到了面试通知,运气也很好背的八股也派上用场,虽然没有一下子变得特别厉害,但是实打实地感觉自己比以前成熟稳重点了。学习过程中发现自己蛮喜欢软开的,也能获得成就感,所以特别感谢二哥一直以来对大家的帮助。
-
-
-
## JDK1.8 新特性
JDK 已经出到 17 了,但是你迭代你的版本,我用我的 8。JDK1.8 的一些新特性,当然现在也不新了,其实在工作中已经很常用了。
diff --git a/docs/src/sidebar/sanfene/javathread.md b/docs/src/sidebar/sanfene/javathread.md
index ec1def96be..339b971690 100644
--- a/docs/src/sidebar/sanfene/javathread.md
+++ b/docs/src/sidebar/sanfene/javathread.md
@@ -1,13 +1,13 @@
---
-title: Java并发编程面试题,73道Java多线程八股文(3.5万字145张手绘图),面渣逆袭必看👍
+title: Java并发编程面试题,71道Java多线程八股文(3.5万字145张手绘图),面渣逆袭必看👍
shortTitle: 面渣逆袭-Java并发编程
author: 三分恶&沉默王二
category:
- 面渣逆袭
tag:
- 面渣逆袭
-description: 下载次数超 1 万次,3.5 万字 145 张手绘图,详解 73 道 Java 多线程面试高频题(让天下没有难背的八股),面渣背会这些并发编程八股文,这次吊打面试官,我觉得稳了(手动 dog)。
-date: 2025-09-19
+description: 下载次数超 1 万次,3.5 万字 145 张手绘图,详解 71 道 Java 多线程面试高频题(让天下没有难背的八股),面渣背会这些并发编程八股文,这次吊打面试官,我觉得稳了(手动 dog)。
+date: 2024-10-08
head:
- - meta
- name: keywords
@@ -19,7 +19,7 @@ head:
## 前言
-3.5 万字 145 张手绘图,详解 73 道 Java 多线程面试高频题(让天下没有难背的八股),面渣背会这些并发编程八股文,这次吊打面试官,我觉得稳了(手动 dog)。
+3.5 万字 145 张手绘图,详解 71 道 Java 多线程面试高频题(让天下没有难背的八股),面渣背会这些并发编程八股文,这次吊打面试官,我觉得稳了(手动 dog)。
第一版作者是二哥编程星球的嘉宾三分恶,第二版由二哥结合球友们的面经+技术派+PmHub+mydb 的项目进行全新升级。更适合拿来背诵突击面试+底层原理理解。
@@ -165,9 +165,7 @@ fun main() = runBlocking {
> 10. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的vivo 面经同学 10 技术一面面试原题:线程的概念,线程有哪些状态
> 11. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的海康威视同学 4面试原题:对协程的了解,为什么协程比线程还有更低的资源消耗
-memo:2025 年 8 月 17 日修改至此。[今天在帮球友修改简历的时候](https://javabetter.cn/zhishixingqiu/jianli.html),收到他的反馈说:上次也麻烦我帮他改了改简历,也顺利找到了实习,秋招逼近,希望我能再帮他看看实习经历。感谢球友的每一次口碑。
-
-
+memo:2025 年 1 月 23 日修改至此。
### 3.🌟说说线程有几种创建方式?
@@ -292,14 +290,6 @@ Thread: Finalizer (ID=3)
- `Thread: Signal Dispatcher (ID=4)` - 信号调度线程,处理来自操作系统的信号,将它们转发给 JVM 进行进一步处理,例如响应中断、停止等信号。
- `Thread: Monitor Ctrl-Break (ID=5)` - 监视器线程,通常由一些特定的 IDE 创建,用于在开发过程中监控和管理程序执行或者处理中断。
-#### 你平时有用过多线程吗?你在代码中是哪些场景用呢?
-
-用得比较多,批量数据处理、异步任务处理、定时任务调度都需要用到多线程。
-
-比如说在[技术派的首页内容加载](https://javabetter.cn/zhishixingqiu/paicoding.html)中,就用到了多线程来并行加载不同的模块,提高页面的响应速度。
-
-
-
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动面经同学 1 Java 后端技术一面面试原题:有多少种实现线程的方法?
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的农业银行同学 1 面试原题:实现线程的方式和区别
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的农业银行面经同学 3 Java 后端面试原题:说说线程的创建方法
@@ -309,9 +299,7 @@ Thread: Finalizer (ID=3)
> 7. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的百度面经同学 1 文心一言 25 实习 Java 后端面试原题:java 如何创建线程?每次都要创建新线程来实现异步操作,很繁琐,有了解线程池吗?
> 8. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团面经同学 4 一面面试原题:平时怎么使用多线程
-memo:2025 年 9 月 26 日修改至此。今天[有球友在星球里](https://javabetter.cn/zhishixingqiu/)报喜说拿到了字节的意向,感谢二哥的面渣逆袭。
-
-
+memo:2025 年 1 月 24 日修改至此。
### 4.🌟调用 start 方法时会执行 run 方法,那怎么不直接调用 run方法?
@@ -1170,25 +1158,6 @@ localVariable.remove();
在数据库操作中,可以使用 ThreadLocal 存储数据库连接对象,每个线程有自己独立的数据库连接,从而避免了多线程竞争同一数据库连接的问题。
-```java
-public class DsContextHolder {
- private static final ThreadLocal CONTEXT_HOLDER = new InheritableThreadLocal<>();
-
- public static void reset() {
- DsNode ds = CONTEXT_HOLDER.get();
- if (ds == null) {
- return;
- }
-
- if (ds.pre != null) {
- CONTEXT_HOLDER.set(ds.pre);
- } else {
- CONTEXT_HOLDER.remove(); // 清除ThreadLocal中的数据
- }
- }
-}
-```
-
在格式化操作中,例如日期格式化,可以使用 ThreadLocal 存储 SimpleDateFormat 实例,避免多线程共享同一实例导致的线程安全问题。
#### ThreadLocal 有哪些优点?
@@ -1205,10 +1174,6 @@ ThreadLocal 可用于跨方法、跨类时传递上下文数据,不需要在
> 5. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的携程面经同学 1 Java 后端技术一面面试原题:ThreadLocal,(作用,演进,软指针,删除过程)
> 6. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团同学 9 一面面试原题:threadlocal的优点?
-memo:2025 年 8 月 23 日修改至此,今天[有球友在 VIP 群里](https://javabetter.cn/zhishixingqiu/)发贴说拿到了美团背景的转正 offer,真的要恭喜啊,8 月下旬就能转正,太舒服了。
-
-
-
### 13.你在工作中用到过 ThreadLocal 吗?
有用到过,用来存储用户信息。
@@ -1229,6 +1194,9 @@ memo:2025 年 8 月 23 日修改至此,今天[有球友在 VIP 群里](https

+
+memo:2025 年 1 月 31 日修改至此。
+
### 14.🌟ThreadLocal 怎么实现的呢?
当我们创建一个 ThreadLocal 对象并调用 set 方法时,其实是在当前线程中初始化了一个 ThreadLocalMap。
@@ -1256,20 +1224,17 @@ static class Entry extends WeakReference> {
}
```
-简版回答:
+总结一下:
ThreadLocal 的实现原理是,每个线程维护一个 Map,key 为 ThreadLocal 对象,value 为想要实现线程隔离的对象。
-- 1、通过 ThreadLocal 的 set 方法将对象存入 Map 中。
-- 2、通过 ThreadLocal 的 get 方法从 Map 中取出对象。
-- 3、Map 的大小由 ThreadLocal 对象的多少决定。
-
-
+1、通过 ThreadLocal 的 set 方法将对象存入 Map 中。
+2、通过 ThreadLocal 的 get 方法从 Map 中取出对象。
-memo:2025 年 9 月 18 日修改至此,今天有 27 届的球友拿到了小红书的日常实习 offer,特意来报喜,还称赞了二哥的面渣逆袭和[派聪明项目](https://javabetter.cn/zhishixingqiu/paismart.html),祝贺!
+3、Map 的大小由 ThreadLocal 对象的多少决定。
-
+
#### 什么是弱引用,什么是强引用?
@@ -1306,9 +1271,7 @@ userThreadLocal 是一个强引用,`new ThreadLocal<>()` 是一个强引用对
> 4. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的携程面经同学 1 Java 后端技术一面面试原题:ThreadLocal,(作用,演进,软指针,删除过程)
> 5. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的虾皮面经同学 13 一面面试原题:threadlocal 原理 怎么避免垃圾回收?
-memo:2025 年 8 月 23 日修改至此。[今天又有球友在 VIP 群里](https://javabetter.cn/zhishixingqiu/)报喜说拿到了美团的转正 offer,并且直言:暑期真的可以冲团子,转正率高达百分百。
-
-
+memo:2025 年 02 月 01 日修改至此。
### 15.🌟ThreadLocal 内存泄露是怎么回事?
@@ -1362,36 +1325,6 @@ public void clear() {

-#### 你每次操作都会remove吗?
-
-我不是每次操作都 remove,主要是根据使用场景来决定的。在一些短生命周期的场景中,比如处理单个 HTTP 请求的上下文信息,我通常会在请求结束时统一 remove。
-
-```java
-public class ReqInfoContext {
- private static TransmittableThreadLocal contexts = new TransmittableThreadLocal<>();
-
- public static void addReqInfo(ReqInfo reqInfo) {
- contexts.set(reqInfo);
- }
-
- public static void clear() {
- contexts.remove(); // 清除ThreadLocal中的数据
- }
-
- public static ReqInfo getReqInfo() {
- return contexts.get();
- }
-}
-```
-
-但在一些需要跨多个方法调用保持状态的场景中,就不会每次都 remove。
-
-我的使用原则是:
-
-- 在方法级别使用时,try-finally 保证 remove
-- 在请求级别使用时,通过拦截器或 Filter 统一清理
-- 如果存储的对象比较大,使用完立即 remove
-- 定期检查 ThreadLocal 的使用情况,避免遗漏
#### 那为什么 key 要设计成弱引用?
@@ -1453,9 +1386,7 @@ String value = context.get();
> 5. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的携程面经同学 1 Java 后端技术一面面试原题:ThreadLocal,(作用,演进,软指针,删除过程)
> 6. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团同学 9 一面面试原题:threadlocal他会出现什么问题?出现内存泄漏怎么解决?
-memo:2025 年 08 月 23 日修改至此。今天[在帮球友修改简历](https://javabetter.cn/zhishixingqiu/jianli.html)的时候,收到这样一个反馈:1 月份加入星球,3 月份拿到一个小日常,后面又拿到了蚂蚁的暑期,周三答辩,转正没什么问题。真的非常感谢球友们的正反馈,这是我一路坚持下去的最强动力。
-
-
+memo:2025 年 02 月 02 日修改至此。
### 16.ThreadLocalMap 的源码看过吗?
@@ -1999,20 +1930,18 @@ volatile_write(); // 写入 volatile 变量
StoreLoad; // 保证写入后,其他线程立即可见
```
----这部分面试中可以不背 start---
在 x86 架构下,通常会使用 `lock` 指令来实现写屏障,例如:
```
mov [a], 2 ; 将值 2 写入内存地址 a
lock add [a], 0 ; lock 指令充当写屏障,确保内存可见性
```
----这部分面试中可以不背 end---
当线程对 volatile 变量进行读操作时,JVM 会插入一个读屏障指令,这个指令会强制让本地内存中的变量值失效,从而重新从主内存中读取最新的值。

-当声明一个 volatile 变量 x:
+我们来声明一个 volatile 变量 x:
```java
volatile int x = 0
@@ -2031,88 +1960,6 @@ JVM 会在 volatile 变量的读写前后插入 “内存屏障”,以约束 C
- LoadLoad 屏障会禁止 volatile 读与后续普通读操作重排
- LoadStore 屏障会禁止 volatile 读与后续普通写操作重排
-#### 单线程下不加volatile和加volatile性能开销有很大区别吗?
-
-单线程下,volatile 的性能开销相对较小,因为没有线程竞争和上下文切换的开销。
-
-但 volatile 仍然会引入一些额外的内存屏障指令,以确保内存可见性。我之前做过一个测试,普通变量1亿次操作只用了2-3毫秒,volatile 变量 1亿次操作用了25-29毫秒,大概是普通变量的 10 倍左右。
-
-
-
-虽然相对差异很大,但绝对时间差异很小,都是毫秒级。
-
-#### volatile不是会强制写和查主内存吗,这样不会影响性能吗,像AQS等等java的工具都有用到volatile,他们是怎么解决这个性能问题的
-
-volatile 确实会带来一些开销,主要包括:
-
-- 禁止 CPU 缓存优化,每次都要同步到主内存
-- 插入内存屏障,防止指令重排序
-- 在某些架构上,会导致 CPU 缓存行失效
-
-但是!现代 CPU 和 JVM 都做了大量优化,volatile 的开销已经降低到可以接受的范围。
-
-第一,现代 CPU 都有多级缓存(L1、L2、L3),volatile 变量虽然不能在寄存器中缓存,但还是可以利用 CPU 缓存的。
-
-
-
-只是需要通过缓存一致性协议(MESI)来保证可见性。
-
-
-
-```
-// 比如在x86架构下
-volatile int state = 0;
-// 读操作:会从L1/L2/L3缓存读,只要缓存行是最新的
-// 写操作:写入缓存,同时通过MESI协议通知其他CPU缓存失效
-```
-
-第二,JVM 会根据不同的 CPU 架构选择最优的内存屏障实现:
-
-```
-// x86架构下,volatile写入的汇编大致是:
-// mov [内存地址], 寄存器 // 普通写入
-// lock addl $0, (%rsp) // 内存屏障,但x86的强内存模型下开销很小
-
-// ARM架构下需要更多屏障:
-// str 寄存器, [内存地址] // 写入
-// dmb sy // 数据内存屏障
-```
-
-AQS 的设计非常精妙,只在绝对必要的地方使用 volatile。比如 state 必须是 volatile,因为所有线程都要看到最新值,但 Node 中的 nextWaiter 就不需要,因为它只在持有锁的情况下访问。
-
-```java
-public abstract class AbstractQueuedSynchronizer {
- // 只有state是volatile的
- private volatile int state;
-
- // 队列节点大部分字段都不是volatile
- static final class Node {
- volatile Node prev; // 需要保证可见性的才用volatile
- volatile Node next;
- volatile Thread thread;
- Node nextWaiter; // 不需要强一致性的就不用volatile
- }
-}
-```
-
-AQS 大量使用 Unsafe 类进行更细粒度的控制:
-
-```java
-// 普通的volatile读写
-volatile int state;
-int s = state; // volatile读
-state = s + 1; // volatile写
-
-// AQS使用Unsafe
-private static final Unsafe unsafe = Unsafe.getUnsafe();
-private static final long stateOffset;
-
-// 可以选择性地使用不同级别的内存语义
-unsafe.getInt(this, stateOffset); // 普通读
-unsafe.getIntVolatile(this, stateOffset); // volatile读
-unsafe.compareAndSwapInt(this, stateOffset, expect, update); // CAS
-```
-
#### volatile 和 synchronized 的区别?
volatile 关键字用于修饰变量,确保该变量的更新操作对所有线程是可见的,即一旦某个线程修改了 volatile 变量,其他线程会立即看到最新的值。
@@ -2149,9 +1996,7 @@ private volatile SomeObject obj = new SomeObject();
-memo:2025 年 9 月 20 日修改至此,[今天有球友](https://javabetter.cn/zhishixingqiu/)在咨询问题的时候,提到自己腾讯暑期转正了,那么恭喜他,真的太强了。鹅厂可以说是国内最好的互联网公司了,没有之一。
-
-
+memo:2025 年 02 月 08 日修改至此,昨天主要是做 [deepseek API 技术派的集成](https://mp.weixin.qq.com/s/F6BOxQvRELUJaU_O4dmwmQ)。
## 锁
@@ -2254,9 +2099,7 @@ ObjectMonitor() {
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的去哪儿面经同学 1 技术二面面试原题:synchronized 底层,会不会牵扯到 os 层面
-memo:2025 年 9 月 24 日修改至此。今天[有球友在星球](https://javabetter.cn/zhishixingqiu/)发咨询说拿到了美团的日常实习 offer,问后面还要不要再找一段,那这里必须先恭喜一下他,明年三四月份可以直接暑期实习了。
-
-
+memo:2025 年 02 月 09 日修改至此。
### 28.synchronized 怎么保证可见性?
@@ -2381,23 +2224,12 @@ memo:2025 年 02 月 10 日修改至此。
推荐阅读:[偏向锁、轻量级锁、重量级锁到底是什么?](https://javabetter.cn/thread/synchronized.html)
-JDK 1.6 的时候,为了提升 synchronized 的性能,引入了锁升级机制,从低开销的锁可以最大程度减少锁的竞争。
+JDK 1.6 的时候,为了提升 synchronized 的性能,引入了锁升级机制,从低开销的锁逐步升级到高开销的锁,以最大程度减少锁的竞争。

没有线程竞争时,就使用低开销的“偏向锁”,此时没有额外的 CAS 操作;轻度竞争时,使用“轻量级锁”,采用 CAS 自旋,避免线程阻塞;只有在重度竞争时,才使用“重量级锁”,由 Monitor 机制实现,需要线程阻塞。
-#### synchronized 为什么没有锁降级?
-
-主要原因我认为是降级的收益不大。降级不是简单地把标志位改一下就完事。重量级锁涉及到操作系统的互斥量(mutex),还有等待队列、阻塞线程。要降级的话,需要确保:
-
-- 没有线程在等待队列中
-- 当前没有竞争发生
-- 要安全地释放系统资源
-- 要重新初始化轻量级锁的状态
-
-这一套检查和操作下来,开销不小。而且什么时候检查?每次释放锁都检查?性能损耗太大了。
-
#### 了解 synchronized 四种锁状态吗?
了解。
@@ -2481,9 +2313,7 @@ JDK 1.6 的时候,为了提升 synchronized 的性能,引入了锁升级机
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的去哪儿面经同学 1 技术二面面试原题:锁升级,synchronized 底层,会不会牵扯到 os 层面
> 4. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的快手同学 2 一面面试原题:锁升级的过程?
-memo:2025 年 09 月 11 日修改至此。synchronized 的锁升级是一块非常重要的内容,第二版的优化对这块内容进行了重新梳理,自认为更容易懂了,等大家的实际效果。今天有腾讯转正的球友在简历修改的邮件里提到:面渣逆袭写的真好,真的很感谢认可。
-
-
+memo:2025 年 02 月 11 日修改至此。synchronized 的锁升级是一块非常重要的内容,第二版的优化对这块内容进行了重新梳理,自认为更容易懂了,等大家的实际效果。
### 30.🌟synchronized 和 ReentrantLock 的区别了解吗?
@@ -2871,9 +2701,8 @@ class Account {
```
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的携程面经同学 1 Java 后端技术一面面试原题:cas 和 aba(原子操作+时间戳)
-> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的Oppo面经同学 15 线下面试原题:CAS操作,带来哪些问题
-memo:2025 年 2 月 13 日修改至此,[VIP 群里](https://javabetter.cn/zhishixingqiu/)已经有球友在催下一个主题了,说实话最近事情有点多,认真修改起来又会比较花时间,所以只能希望大家多理解了。
+memo:2025 年 2 月 13 日修改至此,VIP 群里已经有球友在催下一个主题了,说实话最近事情有点多,认真修改起来又会比较花时间,所以只能希望大家多理解了。

@@ -3623,10 +3452,6 @@ JDK 8 使用了一种更加细粒度的锁——桶锁,再配合 CAS + synchro
对于写操作,ConcurrentHashMap 优先使用 CAS 尝试插入,如果成功就直接返回;否则使用 synchronized 代码块进行加锁处理。
-memo:2025 年 9 月 19 日修改至此,今天[有球友在 VIP 群里](https://javabetter.cn/zhishixingqiu/)报喜说拿到了美团的 offer,那么必须恭喜他🎉,现在是 9 月中旬,大家一定要扛住哦,胜利就在前方。
-
-
-
#### 说一下 JDK 7 中 ConcurrentHashMap 的实现原理?
好的。
@@ -3825,7 +3650,7 @@ JDK 1.7 中的 ConcurrentHashMap 使用了分段锁机制,每个 Segment 都
> 12. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的快手同学 4 一面原题:刚刚提到了Spring使用ConcurrentHashMap来实现单例模式,大致说下ConcurrentHashMap的put和get方法流程?
> 13. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯面经同学 29 Java 后端一面原题:ConcurrentHashMap底层是怎么实现的?
-memo:2025 年 2 月 20 日修改至此,今天要[修改大量简历](https://javabetter.cn/zhishixingqiu/jianli.html),所以面渣逆袭的进度只能耽误一下了。
+memo:2025 年 2 月 20 日修改至此,今天要修改大量简历,所以面渣逆袭的进度只能耽误一下了。

@@ -3890,13 +3715,11 @@ public V get(Object key) {
> 2024 年 04 月 23 日增补,推荐阅读:[吊打 Java 并发面试官之 CopyOnWriteArrayList](https://javabetter.cn/thread/CopyOnWriteArrayList.html)
-CopyOnWriteArrayList 是 ArrayList 的线程安全版本,适用于读多写少的场景。
-
-CopyOnWrite 的核心思想是写操作时创建一个新数组,修改后再替换原数组,这样就能够确保读操作无锁,从而提高并发性能。
+CopyOnWriteArrayList 是 ArrayList 的线程安全版本,适用于读多写少的场景。它的核心思想是写操作时创建一个新数组,修改后再替换原数组,这样就能够确保读操作无锁,从而提高并发性能。

-内部使用 volatile 变量来修饰数组 array,以确保读操作的内存可见性。
+内部使用 volatile 变量来修饰数组 array,以读操作的内存可见性。
```java
private transient volatile Object[] array;
@@ -3930,10 +3753,6 @@ public boolean add(E e) {
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯云智面经同学 16 一面面试原题:ConcurrentHashMap、CopyOnWriteArrayList 的实现原理?
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯面经同学 26 暑期实习微信支付面试原题:说一说常用的并发容器
-memo:2025 年 8 月 19 日修改至此,今天在[帮球友修改简历](https://javabetter.cn/zhishixingqiu/jianli.html)的时候,碰到这样一段正反馈:暑期 6 月底靠二哥改的简历救命拿了一家近千人的小厂实习,跪谢一波。实习润了[派聪明](https://javabetter.cn/zhishixingqiu/paismart.html),刚好和公司的智能助手匹配。
-
-
-
### 52. 能说一下 BlockingQueue 吗?(补充)
> 2024 年 08 月 18 日增补,从集合框架移动到并发编程这里
@@ -3998,10 +3817,6 @@ memo:2025 年 02 月 21 日修改至此。今天的主要工作仍然是[修
举个例子:就像你开了一家餐厅,线程池就相当于固定数量的服务员,顾客(任务)来了就安排空闲的服务员(线程)处理,避免了频繁招人和解雇的成本。
-#### 线程池里面的任务队列是什么队列?
-
-阻塞队列。
-
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的小米春招同学 K 一面面试原题:说一下为什么项目中使用线程池,重要参数,举个例子说一下这些参数的变化
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动同学 7 Java 后端实习一面的原题:讲一下为什么引入线程池?
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的微众银行同学 1 Java 后端一面的原题:说说你对线程池的理解
@@ -4171,7 +3986,7 @@ class ThreadPoolDemo {
**③、workQueue**:任务队列,存储等待执行的任务。
-**④、handler**:拒绝策略,任务超载时的处理方式。也就是线程数达到 maximumPoolSize,任务队列也满了的时候,就会触发拒绝策略。
+**④、handler**:拒绝策略,任务超载时的处理方式。也就是线程数达到 maximumPoolSiz,任务队列也满了的时候,就会触发拒绝策略。
**⑤、threadFactory**:线程工厂,用于创建线程,可自定义线程名。
@@ -4338,9 +4153,7 @@ public static ExecutorService newCachedThreadPool() {
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的微众银行同学 1 Java 后端一面的原题:线程池的阻塞队列有哪些实现方式?
-memo:2025年 9 月 04 日修改至此,今天在帮球友修改简历的时候,有球友反馈,靠[二哥修改的简历](https://javabetter.cn/zhishixingqiu/jianli.html)拿到了字节的实习,现在秋招,希望能继续优化一下简历。
-
-
+memo:2025 年 2 月 22 日修改至此。
### 59.线程池提交 execute 和 submit 有什么区别?
@@ -4460,9 +4273,7 @@ jstack | grep -A 20 "BLOCKED" // 查看阻塞线程
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的oppo 面经同学 8 后端开发秋招一面面试原题:线程池都有哪些以及核心参数介绍下
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的理想汽车面经同学 2 一面面试原题:JAVA中线程池有哪些?
-memo:2025 年 8 月 17 日修改至此。[今天收到球友的反馈说](https://javabetter.cn/zhishixingqiu/),偶然的机会加入了星球,学习下来感觉还挺好的,感谢球友每一次的口碑,笔芯芯。
-
-
+memo:2025 年 2 月 23 日修改至此。
### 63.能说一下四种常见线程池的原理吗?
@@ -4681,8 +4492,6 @@ memo:2025 年 2 月 24 日修改至此。今天是出考研成绩的一天,
> 2024 年 03 月 16 日增补,推荐阅读:[Java线程池实现原理及其在美团业务中的实践](https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html)
-线程池的配置优化是针对多线程应用性能调优的关键环节。
-

首先我会根据任务类型设置核心线程数参数,比如 IO 密集型任务会设置为 CPU 核心数\*2 的经验值。
@@ -4691,10 +4500,6 @@ memo:2025 年 2 月 24 日修改至此。今天是出考研成绩的一天,
最后,我会通过内置的监控指标建立容量预警机制。比如通过 JMX 监控线程池的运行状态,设置阈值,当线程池的任务队列长度超过阈值时,触发告警。
-memo:2025 年 9 月 26 日优化至此,今天有球友在 VIP 群里讲,投了 1 天就接面了,[二哥改的简历还是太好用](https://javabetter.cn/zhishixingqiu/jianli.html)。很感谢他的认可。
-
-
-
### 68.线程池在使用的时候需要注意什么?(补充)
> 2024 年 03 月 16 日增补
@@ -4999,26 +4804,7 @@ class SimpleConnectionPool {
## 并发容器和框架
-### 71.并发容器有哪些?
-
-Java 提供了多种并发容器,主要包括:
-
-1. **ConcurrentHashMap**:线程安全的哈希表,支持高并发读写操作。
-2. **CopyOnWriteArrayList**:写时复制的 ArrayList,适用于读多写少的场景。
-3. **BlockingQueue**:阻塞队列,常用实现有 ArrayBlockingQueue 和 LinkedBlockingQueue,适用于生产者-消费者场景。
-4. **ConcurrentLinkedQueue**:非阻塞的线程安全队列。
-5. **ConcurrentSkipListMap**:基于跳表实现的线程安全有序 Map。
-
-> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动面经同学 34 Java 后端技术一面面试原题:并发容器有哪些?
-
-### 72.说说 Java 的并发关键字?
-
-最常用的有两个关键字,分别是:
-
-1. **synchronized**:用于方法或者代码块,确保同一时间只有一个线程可以执行被 synchronized 修饰的代码,适用于保护共享资源的访问。
-2. **volatile**:用于变量,确保变量的可见性,防止指令重排序,适用于状态标志等场景。
-
-### 73.Fork/Join 框架了解吗?
+### 71.Fork/Join 框架了解吗?
关于 Fork/Join 框架,我了解一些,它是 Java 7 引入的一个并行框架,主要用于分治算法的并行执行。这个框架通过将大的任务递归地分解成小任务,然后并行执行,最后再合并结果,以达到最高效率处理大量数据的目的。
@@ -5159,7 +4945,7 @@ memo:2025 年 2 月 26 日修改至此。终于搞定,面渣逆袭并发编
---
-图文详解 73 道 Java 并发面试高频题,这次面试,一定吊打面试官。
+图文详解 71 道 Java 并发面试高频题,这次面试,一定吊打面试官。
_没有什么使我停留——除了目的,纵然岸旁有玫瑰、有绿荫、有宁静的港湾,我是不系之舟_。
diff --git a/docs/src/sidebar/sanfene/jvm.md b/docs/src/sidebar/sanfene/jvm.md
index e764e89413..5a090456f1 100644
--- a/docs/src/sidebar/sanfene/jvm.md
+++ b/docs/src/sidebar/sanfene/jvm.md
@@ -68,28 +68,13 @@ JVM,也就是 Java 虚拟机,它是 Java 实现跨平台的基石。
这样就实现了 Java 一次编译,处处运行的特性。
-#### 如果我们要执行hello world,那虚拟机干了什么呢?谁把字节码翻译成机器码,操作时机是什么?Java虚拟机是一个执行单元吗?
-
-当我们写好一个 HelloWorld 程序,编译成 .class 文件后,执行 `java HelloWorld` 这条命令时,操作系统会创建一个 JVM 进程,JVM 进程启动起来后,会先初始化运行环境,包括创建类加载器、初始化内存空间、启动垃圾回收线程等等。
-
-接下来,JVM 的类加载器会去找 HelloWorld.class 这个文件,读取它的字节码内容。
-
-JVM 的执行引擎会将这些字节码翻译成机器码,有两种方式:
-
-- 第一种是解释执行。JVM 的解释器会逐条读取字节码指令,然后把它翻译成机器码执行。这个过程是动态的,每次执行都要翻译一遍。所以解释执行的速度相对较慢。
-- 第二种是即时编译。JVM 里有一个 JIT 编译器,他发现某段代码被频繁执行(比如循环里的代码或者热点方法)时,JIT 编译器就会把这段字节码直接编译成本地机器码并缓存到 codeCache 中,下次执行的时候不用再一行一行的解释,而是直接执行缓存后的机器码,执行效率会大幅提高。
-
-至于执行的时机,解释器的执行是立即的,当 JVM 启动后,就开始解释执行字节码了。JIT 编译器的执行时机是延后的,它需要先监控哪些代码是热点代码(通常需要执行数千次或者数万次),然后才会启动编译。
-
-操作系统层面,JVM 进程是一个执行单元,由操作系统调度执行。
-
#### 说说 JVM 的其他特性?
①、JVM 可以自动管理内存,通过垃圾回收器回收不再使用的对象并释放内存空间。
②、JVM 包含一个即时编译器 JIT,它可以在运行时将热点代码缓存到 codeCache 中,下次执行的时候不用再一行一行的解释,而是直接执行缓存后的机器码,执行效率会大幅提高。
-
+
③、任何可以通过 Java 编译的语言,比如说 Groovy、Kotlin、Scala 等,都可以在 JVM 上运行。
@@ -108,9 +93,6 @@ JVM 的执行引擎会将这些字节码翻译成机器码,有两种方式:
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的京东同学 10 后端实习一面的原题:有了解 JVM 吗
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动同学 20 测开一面的原题:了解过 JVM 么?讲一下 JVM 的特性
-memo:2025 年 11 月 6 日修改至此,[今天有球友](https://javabetter.cn/zhishixingqiu/)提问说拿到了京东测开的 offer,60 万总包;还有华为的 14a offer,真的恭喜他,太强了呀。
-
-
### 2.说说 JVM 的组织架构(补充)
@@ -120,7 +102,7 @@ memo:2025 年 11 月 6 日修改至此,[今天有球友](https://javabetter.
JVM 大致可以划分为三个部分:类加载器、运行时数据区和执行引擎。
-
+
① 类加载器,负责从文件系统、网络或其他来源加载 Class 文件,将 Class 文件中的二进制数据读入到内存当中。
@@ -128,41 +110,9 @@ JVM 大致可以划分为三个部分:类加载器、运行时数据区和执
③ 执行引擎,也是 JVM 的心脏,负责执行字节码。它包括一个虚拟处理器、即时编译器 JIT 和垃圾回收器。
-#### JVM 是个什么东西?
-
-JVM 本质上就是一个进程。当我们执行 `java -jar application.jar` 命令时,操作系统会创建一个名为 JVM 的进程。这个进程在内存里运行着一个虚拟机,这个虚拟机有自己的指令集、内存模型、执行引擎等等。
-
-#### Java虚拟机和操作系统的关系到底什么,假如我是个完全不懂技术的人,举例说明让我明白
-
-想象操作系统是一个大剧院。这个剧院有舞台、灯光、音响、观众座位等各种资源。剧院的管理员负责分配这些资源,决定谁在什么时候用哪个舞台。
-
-现在,一个话剧团想在这个剧院里演一场就在河南。话剧团就向剧院管理员说:"我需要租用你的舞台、灯光、音响,从下午 2 点到 5 点。"剧院管理员就给他们分配了一个舞台和相关资源。
-
-
-
-操作系统是底层,它直接控制硬件资源,比如 CPU、内存、磁盘、网络等。操作系统的工作就是把这些硬件资源分配给各个应用程序使用。
-
-JVM 是运行在操作系统上的一个应用程序。JVM 本身是一个进程,也就是说,从操作系统的角度看,JVM 就是一个普通的应用程序,并没有什么特别的。操作系统不知道也不关心 JVM 里面运行的是什么,它只是按照进程管理的规则来管理 JVM 这个进程。
-
-### 一个操作系统有两个Java程序的话,有几个虚拟机?有没有单独的JVM进程存在?启动一个hello world编译的时候,有几个进程
-
-1、每一个 Java 程序都需要一个独立的 JVM 进程来运行,两个 Java 程序就需要两个 JVM。这两个 JVM 进程是完全独立的,互不干扰。
-
-2、JVM 不存在什么公共的、被所有 Java 程序共享的进程。每一个 Java 程序都必须启动自己的 JVM 进程。
-
-3、如果只是编译,不运行,至少有两个进程。一个是 javac 的编译器进程。当执行 `javac HelloWorld.java` 时,操作系统会创建一个 javac 进程,这个进程会读取 .java 源文件,生成 .class 字节码文件。完成后 javac 进程就退出了。另一个是当前的 shell 进程,运行 javac 进程的终端,这是一直存在的。
-
-#### JVM什么时候启动 比如执行一条Java命令的时候对应一个进程,然后这个JVM虚拟机到底是不是在这个进程里面,还是说要先启动一个JVM虚拟机的进程
-
-当执行 `java HelloWorld` 这条命令的时候,操作系统就会创建 JVM 进程。没有"先启动 JVM"然后"再运行程序"这种操作。而是一步到位:操作系统启动了 JVM 进程,JVM 进程同时运行 Java 程序。
-
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯 Java 后端实习一面原题:说说 JVM 的组织架构
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的得物面经同学 9 面试题目原题:JVM的架构,具体阐述一下各个部分的功能?
-memo:2025 年 11 月 04 日修改至此,[今天有球友](https://javabetter.cn/zhishixingqiu/)私信说美团开奖了,白菜,但今年美团整体开的都是这个价,24k 左右,去年其实也差不多这个价,好在美团业务稳定,整体氛围还可以。
-
-
-
## 二、内存管理
### 3.🌟能说一下 JVM 的内存区域吗?
@@ -384,10 +334,6 @@ G1|| -XX:+UseG1GC
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团面经同学 2 Java 后端技术一面面试原题:说说创建对象的流程?
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的携程面经同学 1 Java 后端技术一面面试原题:对象创建到销毁,内存如何分配的,(类加载和对象创建过程,CMS,G1 内存清理和分配)
-memo:2025 年 8 月 13 日修改到此,[就像球友说的](https://javabetter.cn/zhishixingqiu/),帮大家拿下暑期实习,也会帮大家拿下秋招。
-
-
-
### 7.堆内存是如何分配的?
在堆中为对象分配内存时,主要使用两种策略:指针碰撞和空闲列表。
@@ -472,13 +418,15 @@ class TLABDemo {
直接出现了两次 GC,因为没有 TLAB,Eden 区更快被填满,导致年轻代 GC。年轻代 GC 频繁触发,一部分长生命周期对象被晋升到老年代,间接导致老年代 GC 触发。
-### 9.🌟能说一下对象的内存布局吗?
+### 9.能说一下对象的内存布局吗?
好的。
对象的内存布局是由 Java 虚拟机规范定义的,但具体的实现细节各有不同,如 HotSpot 和 OpenJ9 就不一样。
-就拿我们常用的 HotSpot 来说吧。对象在内存中包括三部分:对象头、实例数据和对齐填充。
+就拿我们常用的 HotSpot 来说吧。
+
+对象在内存中包括三部分:对象头、实例数据和对齐填充。

@@ -639,11 +587,8 @@ ReferenceHolder.reference 的大小为 4 字节。
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的帆软同学 3 Java 后端一面的原题:Object a = new object()的大小,对象引用占多少大小?
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的去哪儿面经同学 1 技术二面面试原题:Object 底层的数据结构(蒙了)
-> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的京东同学 19 JDS 后端一面的原题:一个对象的结构是什么,包含哪些内容
-memo:2025 年 8 月 14 日修改到此。[今天收到球友的反馈说](https://javabetter.cn/zhishixingqiu/),暑期拒了腾讯的客户端,暑期实习已经拿到了美团的意向,坐等 A 薪资。😄
-
-
+memo:2025 年 1 月 11 日修改到此
### 10.JVM 怎么访问对象的?
@@ -1187,7 +1132,7 @@ public class LargeLocalVariables {
> 本题是增补的内容,by 2024 年 03 月 09 日;参照:[深入理解 JVM 的垃圾回收机制](https://javabetter.cn/jvm/gc.html)
-垃圾回收就是对堆内存中已经死亡的或者长时间没有使用的对象进行清除或回收。
+垃圾回收就是对内存堆中已经死亡的或者长时间没有使用的对象进行清除或回收。
JVM 在做 GC 之前,会先搞清楚什么是垃圾,什么不是垃圾,通常会通过可达性分析算法来判断对象是否存活。
@@ -1209,73 +1154,6 @@ java -XX:+UseConcMarkSweepGC \
Java 的垃圾回收过程主要分为标记存活对象、清除无用对象、以及内存压缩/整理三个阶段。不同的垃圾回收器在执行这些步骤时会采用不同的策略和算法。
-
-
-#### 哪些阶段会触发 STW?
-
-STW 是 JVM 为了垃圾回收而暂停所有用户线程的机制。
-
-
-
-总结一下:在标记阶段,STW 是必需的。无论是哪种垃圾回收算法,标记阶段都需要准确找出所有存活对象。如果标记的时候业务线程还在运行,就会标记不准确。因为业务线程可能会在 GC 标记某个对象为垃圾的同时,访问这个对象。为了避免这种冲突,标记阶段必须暂停所有业务线程。
-
-在清除阶段,是否需要 STW 取决于算法的实现。
-
-如果使用的是复制算法或标记-整理算法(需要移动对象),那就必须 STW。因为对象被移动后,所有指向这个对象的引用都要更新,这个过程中不能让业务线程访问这些对象。
-
-如果使用的是标记-清除算法(不移动对象),理论上可以不 STW,业务线程和 GC 线程可以并发执行。
-
-对于新生代的垃圾收集器 Serial 和 ParNew,整个垃圾回收过程都会触发 STW,但因为年轻代小,通常很快(几毫秒到几十毫秒)。
-
-```
-1. 初始标记(STW)
- - 暂停所有用户线程
- - 标记 GC Roots 直接引用的对象
-
-2. 复制存活对象(STW)
- - 将 Eden 和 Survivor0 中的存活对象复制到 Survivor1
- - 清空 Eden 和 Survivor0
-
-3. 更新引用(STW)
- - 更新所有指向移动对象的引用
-```
-
-CMS 在此基础上进行了改进,通过并发执行来减少 STW 时间,会在初始标记和重新标记阶段触发 STW。
-
-```
-1. 初始标记 Initial Mark(STW)✅
- - 时间很短
- - 仅标记 GC Roots 直接引用的对象
- - 标记所有年轻代对象引用的老年代对象
-
-2. 并发标记 Concurrent Mark(并发执行)
- - 用户线程继续运行
- - GC 线程遍历整个对象图
- - 标记所有存活对象
-
-3. 重新标记 Remark(STW)✅
- - 修正并发标记期间的变化
- - 使用增量更新算法
- - 这个阶段时间比初始标记长
-
-4. 并发清除 Concurrent Sweep(并发执行)
- - 用户线程继续运行
- - 清理未标记的对象
- - 不进行压缩,会产生碎片
-```
-
-G1 采用的是增量回收的思想,不是一次性把整个堆都清理,而是把堆分成很多小的区域,每次只清理一部分区域。这样就可以分散 STW 的时间,单次 STW 的时间就短了。
-
-ZGC 采用了并发整理的技术,可以在应用线程运行的同时进行对象的整理和移动,几乎消除了 STW 时间。ZGC 的 STW 时间通常在 10 毫秒以内。
-
-#### 垃圾回收机制的时机?能手动触发垃圾回收吗?垃圾回收会抢占业务代码的CPU吗?
-
-1、JVM 会监控堆内存的使用情况,当内存快要不够用时,就会自动触发垃圾回收。
-
-2、理论上能手动触发垃圾回收,JVM 提供了 `System.gc()` 这个方法,可以手动调用它来触发垃圾回收,但一般不建议这么做。
-
-3、垃圾回收会抢占 CPU,垃圾回收时会触发 STW,暂停所有业务线程。Minor GC 的 STW 时间较短,Major GC 的 STW 时间较长。
-
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的华为 OD 技术一面遇到的一道原题。
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团面经同学 2 Java 后端技术一面面试原题:了解 GC 吗?不可达判断知道吗?
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯面经同学 26 暑期实习微信支付面试原题:JVM 垃圾删除
@@ -1289,10 +1167,6 @@ ZGC 采用了并发整理的技术,可以在应用线程运行的同时进行
> 11. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的理想汽车面经同学 2 一面面试原题:说说你对GC的了解?
> 12. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯面经同学 29 Java 后端一面原题:JVM垃圾回收机制?
-memo:2025 年 8 月 19 日修改到此,今天有球友发私信说[加入星球了](https://javabetter.cn/zhishixingqiu/) ,主要是因为[面渣逆袭](https://javabetter.cn/sidebar/sanfene/nixi.html)给他的体验非常不错,真的感谢口碑和支持。
-
-
-
### 24.🌟如何判断对象仍然存活?
Java 通过可达性分析算法来判断一个对象是否还存活。
@@ -1505,10 +1379,6 @@ class ConstantPoolReference {
> 5. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的京东面经同学 9 面试原题:问了垃圾回收算法,针对问了每个算法的优缺点
> 6. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的同学 D 小米一面原题:gc垃圾回收算法有哪些
-memo:2025 年 11 月 03 日,[今天有球友私信](https://javabetter.cn/zhishixingqiu/)问 offer 怎么选,他有一个成都的京东 sp,还有一个抖音电商,都是非常顶级的 offer,真的要恭喜他。
-
-
-
### 28.Minor GC、Major GC、Mixed GC、Full GC 都是什么意思?
Minor GC 也称为 Young GC,是指发生在年轻代的垃圾收集。年轻代包含 Eden 区以及两个 Survivor 区。
@@ -1699,7 +1569,7 @@ G1 在 JDK 1.7 时引入,在 JDK 9 时取代 CMS 成为默认的垃圾收集

-G1 把 Java 堆划分为多个大小相等的独立区域 Region,每个区域都可以扮演新生代或老年代的角色。
+G1 把 Java 堆划分为多个大小相等的独立区域Region,每个区域都可以扮演新生代或老年代的角色。
同时,G1 还有一个专门为大对象设计的 Region,叫 Humongous 区。
@@ -1719,55 +1589,11 @@ G1 收集器的运行过程大致可划分为这几个步骤:

-#### 计算Region的时候怎么和业务代码并行执行
-
-在 G1 中,堆被划分成很多个大小相等的区域,每个区域叫做 Region。G1 的工作方式是,每次不对整个堆进行垃圾回收,而是计算哪些 Region 中的垃圾最多、回收效率最高,然后只回收这些 Region。
-
-```
-┌─────────────────────────────────────────────────┐
-│ Region1 │ Region2 │ Region3 │ Region4 │ Region5 │
-│ 年轻代 │ 年轻代 │ 老年代 │ 老年代 │ 空闲 │
-│ 垃圾: 10%│ 垃圾: 5% │ 垃圾: 70%│ 垃圾: 15%│ │
-└─────────────────────────────────────────────────┘
-```
-
-第一步,G1 会启动一些 GC 标记线程,这些线程和业务线程并发运行。业务线程执行代码,标记线程同时遍历堆中的对象,找出哪些对象是活的,哪些是垃圾。
-
-这里需要用到写屏障(Write Barrier)技术,每当业务线程改变对象的引用时,写屏障就会记录下来:"有个引用被改变了"。GC 线程会根据这些记录来调整标记结果。
-
-```java
-// 简化的写屏障概念示意
-
-class Object {
- Object ref;
-
- // 业务线程执行:obj.ref = newRef;
- // 实际执行过程:
- public void setRef(Object newRef) {
- // 原始操作
- this.ref = newRef;
-
- // 写屏障操作(由 JVM 自动插入)
- writeBarrier(newRef); // 通知 GC:"这个对象的引用被改变了"
- }
-}
-```
-
-第二步,并发计算每个 Region 的垃圾占比。
-
-第三步,G1 根据计算结果选择垃圾最多的几个 Region 进行回收。这时候才会触发 STW,暂停业务线程,对这些 Region 进行垃圾清理。
-
-因为只清理少数几个 Region,而不是整个堆。所以 STW 的时间很短。
-
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的京东面经同学 1 Java 技术一面面试原题:说说 G1 垃圾回收器的原理
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的携程面经同学 1 Java 后端技术一面面试原题:对象创建到销毁,内存如何分配的,(类加载和对象创建过程,CMS,G1 内存清理和分配)
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的百度同学 4 面试原题:G1 垃圾回收器了解吗?
> 4. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的理想汽车面经同学 2 一面面试原题:了解过G1垃圾回收器吗?
-memo:2025 年 9 月 17 日修改至此。今天[有球友特意来感谢星球](https://javabetter.cn/zhishixingqiu/),项目、八股都很有帮助,说那点钱都不好意思麻烦我。哈哈,我就想做这么一个人,让大家花最小的代码就能获得巨大的成长,这样才有口碑嘛。
-
-
-
### 34.有了 CMS,为什么还要引入 G1?
| 特性 | CMS | G1 |
@@ -1898,8 +1724,6 @@ JDK 自带的命令行工具层面,我用过 jps、jstat、jinfo、jmap、jhat
### 39.JVM 的常见参数配置知道哪些?
-答:我自己用过的 JVM 调优参数主要有 `-Xms` 设置初始堆大小,`-Xmx` 设置最大堆大小,`-XX:+UseG1GC` 使用 G1 垃圾收集器,`-XX:MaxGCPauseMillis=n` 设置最大垃圾回收停顿时间,`-XX:+PrintGCDetails` 输出 GC 详细日志等。
-
#### 配置堆内存大小的参数有哪些?
- `-Xms`:初始堆大小
@@ -1929,12 +1753,6 @@ JDK 自带的命令行工具层面,我用过 jps、jstat、jinfo、jmap、jhat
- `-XX:+PrintGCTimeStamps`:输出 GC 的时间戳(以基准时间的形式)
- `-Xloggc:filename`:日志文件的输出路径
->1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的网易面经同学 4 云音乐后端技术面试原题:jvm调优有哪些参数
-
-memo:2025 年 9 月 23 日修改至此。今天在帮球友修改简历的时候,碰到这样一个反馈:没有听二哥的建议修改简历,还用了旧的,结果效果很差,现在已经按照二哥的建议增加了[派聪明 RAG 项目](https://javabetter.cn/zhishixingqiu/paismart.html)到实习经历中,希望二哥能帮忙再看一下。
-
-
-
### 40.做过 JVM 调优吗?
做过。
@@ -1955,10 +1773,6 @@ JVM 调优是一个复杂的过程,调优的对象包括堆内存、垃圾收
### 41.CPU 占用过高怎么排查?
-答:首先,使用 top 命令查看 CPU 占用情况,找到占用 CPU 较高的进程 ID。接着,使用 jstack 命令查看对应进程的线程堆栈信息。然后再使用 top 命令查看进程中线程的占用情况,找到占用 CPU 较高的线程 ID。
-
-接着在 jstack 的输出中搜索这个十六进制的线程 ID,找到对应的堆栈信息。最后,根据堆栈信息定位到具体的业务方法,查看是否有死循环、频繁的垃圾回收、资源竞争导致的上下文频繁切换等问题。
-

首先,使用 top 命令查看 CPU 占用情况,找到占用 CPU 较高的进程 ID。
@@ -2002,25 +1816,8 @@ printf "%x\n" PID
最后,根据堆栈信息定位到具体的业务方法,查看是否有死循环、频繁的垃圾回收、资源竞争导致的上下文频繁切换等问题。
-#### 接口超时的问题排查过吗?
-
-接口超时的排查要从多个层面分析。首先看应用层的监控,比如接口的响应时间分布、错误率、QPS 等指标。
-
-如果有 Skywalking 这种工具,可以看调用链路的详细耗时分布,定位是哪个环节慢了。
-
-
-
-数据库层面要检查慢查询日志,看是不是某些 SQL 执行时间过长。可能是缺少索引、查询条件不合适、或者锁等待。我会用 EXPLAIN 分析 SQL 的执行计划,看是否需要优化。
-
-网络层面也要考虑,比如下游服务响应慢、网络抖动等。可以通过 ping、telnet 等工具测试网络连通性和响应时间。
-
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的阿里面经同学 1 闲鱼后端一面的原题:上线的业务出了问题怎么调试,比如某个线程 cpu 占用率高,怎么看堆栈信息
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的快手同学 4 一面原题:服务器的CPU占用持续升高,有哪些排查问题的手段?排查后发现是项目产生了内存泄露,如何确定问题出在哪里?
-> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的京东同学 19 JDS 面试原题:如果一个线上服务内存、CPU飙高,或者接口超时,说说大概的排查思路?具体可以用哪些工具?
-
-memo:2025 年 8 月 14 日修改至此。 今天在[帮球友修改简历](https://javabetter.cn/zhishixingqiu/jianli.html)的时候(硬件的简历也可以修改的很好哦),碰到这样一个反馈:专业是硬件方向,也几乎每天看二哥的文章,😄
-
-
### 42.内存飙高问题怎么排查?
@@ -2028,7 +1825,9 @@ memo:2025 年 8 月 14 日修改至此。 今天在[帮球友修改简历](htt
排查的方法主要分为以下几步:
-第一,先观察垃圾回收的情况,可以通过 `jstat -gc PID 1000` 查看 GC 次数和时间。或者使用 `jmap -histo PID | head -20` 查看堆内存占用空间最大的前 20 个对象类型。
+第一,先观察垃圾回收的情况,可以通过 `jstat -gc PID 1000` 查看 GC 次数和时间。
+
+或者使用 `jmap -histo PID | head -20` 查看堆内存占用空间最大的前 20 个对象类型。
第二步,通过 jmap 命令 dump 出堆内存信息。
@@ -2102,11 +1901,6 @@ jmap -dump:format=b,file=heap pid
假如是因为 GC 参数配置不合理导致的频繁 Full GC,可以通过调整 GC 参数来优化 GC 行为。或者直接更换更适合的 GC 收集器,如 G1、ZGC 等。
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的得物面经同学 8 一面面试原题:Java 中 full gc 频繁,有哪些原因
-> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的网易面经同学 4 云音乐面试原题:如果频繁发生full gc,可以怎么调整,调整什么参数最好
-
-memo:2025 年 9 月 17 日修改至此。今天[有球友在 VIP 群里](https://javabetter.cn/zhishixingqiu/)讲,面试中遇到 90% 的问题都在星球里,百度这边的面试官甚至直接打开二哥的 Java 进阶之路来面试([他在百度实习,已转正(实习面经贴这里了)](https://t.zsxq.com/jTYm3))。
-
-
@@ -2120,29 +1914,15 @@ memo:2025 年 9 月 17 日修改至此。今天[有球友在 VIP 群里](https
JVM 的操作对象是 Class 文件,JVM 把 Class 文件中描述类的数据结构加载到内存中,并对数据进行校验、解析和初始化,最终转化成可以被 JVM 直接使用的类型,这个过程被称为类加载机制。
-
-
其中最重要的三个概念就是:类加载器、类加载过程和双亲委派模型。
- **类加载器**:负责加载类文件,将类文件加载到内存中,生成 Class 对象。
- **类加载过程**:包括加载、验证、准备、解析和初始化等步骤。
- **双亲委派模型**:当一个类加载器接收到类加载请求时,它会把请求委派给父——类加载器去完成,依次递归,直到最顶层的类加载器,如果父——类加载器无法完成加载请求,子类加载器才会尝试自己去加载。
-#### 说说类的加载过程?
-
-类从被加载到 JVM 开始,到卸载出内存,整个生命周期分为七个阶段,分别是载入、验证、准备、解析、初始化、使用和卸载。其中验证、准备和解析这三个阶段统称为连接。
-
-
-
-除去使用和卸载,就是 Java 的类加载过程。这 5 个阶段一般是顺序发生的,但在动态绑定的情况下,解析阶段发生在初始化阶段之后。
-
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的小米暑期实习同学 E 一面面试原题:你了解类的加载机制吗?
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团面经同学 3 Java 后端技术一面面试原题:java 的类加载机制 双亲委派机制 这样设计的原因是什么
-memo:2025 年 9 月 24 日修改至此。今天[有球友在星球里发帖说](https://javabetter.cn/zhishixingqiu/)拿到了京东的 offer,特意感谢了[派聪明RAG](https://javabetter.cn/zhishixingqiu/paismart.html)这个项目,那真的要恭喜他!
-
-
-
### 46.类加载器有哪些?
主要有四种:
@@ -2159,19 +1939,6 @@ memo:2025 年 9 月 24 日修改至此。今天[有球友在星球里发帖说
通过继承`java.lang.ClassLoader`类来实现。
-#### 类加载谁来执行?
-
-类加载由类加载器来执行,JVM 有三个重要的类加载器:启动类加载器、扩展类加载器、应用类加载器。它们遵循双亲委派机制。
-
-
-
-#### 类加载器是个什么东西?
-
-类加载器是 JVM 内部的一个组件。当 JVM 启动时,会在内存里创建几个类加载器实例,这些类加载器的作用就是根据类名去找到对应的 .class 文件,读取字节码内容,然后交给 JVM 进行解析和初始化。
-
-
-
-
### 47.能说一下类的生命周期吗?
一个类从被加载到虚拟机内存中开始,到从内存中卸载,整个生命周期需要经过七个阶段:加载 、验证、准备、解析、初始化、使用和卸载。
@@ -2280,9 +2047,7 @@ DriverManager 使用了线程上下文类加载器来加载 SPI 的实现类,
如 Spring Boot 的 DevTools 通常会自定义类加载器,优先加载新的类版本。
-memo:2025 年 8 月 16 日修改至此。今天在[帮球友修改简历](https://javabetter.cn/zhishixingqiu/jianli.html)的时候,收到这样一个反馈:暑期实习的时候用了[技术派](https://javabetter.cn/zhishixingqiu/paicoding.html),也找我修改了简历,最后也顺利拿到了哈啰实习,非常感谢。
-
-
+memo:2025 年 1 月 19 日修改至此。
### 52.Tomcat 的类加载机制了解吗?
diff --git a/docs/src/sidebar/sanfene/mysql.md b/docs/src/sidebar/sanfene/mysql.md
index 10017ebb6f..2375dc8e5c 100644
--- a/docs/src/sidebar/sanfene/mysql.md
+++ b/docs/src/sidebar/sanfene/mysql.md
@@ -907,10 +907,10 @@ MySQL 8.0 默认的行格式是 DYNAMIC,由COMPACT 演变而来,意味着这
MySQL 支持多种存储引擎,常见的有 MyISAM、InnoDB、MEMORY 等。
-
-
---这部分是帮助大家理解 start,面试中可不背---
+
+
我来做一个表格对比:
| 功能 | InnoDB | MyISAM | MEMORY |
@@ -1337,8 +1337,6 @@ binlog 是追加写入的,文件写满后会新建文件继续写入,不会
另外,为保证两种日志的一致性,innodb 采用了两阶段提交策略,redo log 在事务执行过程中持续写入,并在事务提交前进入 prepare 状态;binlog 在事务提交的最后阶段写入,之后 redo log 会被标记为 commit 状态。
-
-
可以通过回放 binlog 实现数据同步或者恢复到指定时间点;redo log 用来确保事务提交后即使系统宕机,数据仍然可以通过重放 redo log 恢复。
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团同学 2 优选物流调度技术 2 面面试原题:redo log、bin log
@@ -2504,7 +2502,7 @@ memo:2025 年 3 月 29 日修改至此,今天[有球友说](https://javabett
除了查得快,索引还能加速排序、分组、连接等操作。
-项目中最常见的做法就是通过 `create index` 为经常用作查询条件的字段建索引,比如:
+可以通过 `create index` 创建索引,比如:
```sql
create index idx_name on students(name);
@@ -3752,7 +3750,6 @@ memo:2025 年 04 月 07 日增补至此,今天[有球友反馈](https://java
>empname 和 job 两个字段是一个联合索引,而查询也恰好是这两个字段,这时候单次查询就可以达到目的,不需要回表。
可以将高频查询的字段(如 WHERE 条件和 SELECT 列)组合为联合索引,实现覆盖索引。
-
例如:
```sql
@@ -4458,8 +4455,6 @@ T2 在插入 `(7, 7, '王五')` 时,会被阻塞,可以在另外一个会话
推荐阅读:[六个案例搞懂间隙锁](https://www.51cto.com/article/779551.html)、[MySQL中间隙锁的加锁机制](https://blog.csdn.net/javaanddonet/article/details/111187345)
----- 这部分是帮助大家理解 end,面试中可不背 ----
-
#### 执行什么命令会加上间隙锁?
在可重复读隔离级别下,执行 FOR UPDATE / LOCK IN SHARE MODE 等加锁语句,且查询条件是范围查询时,就会自动加上间隙锁。
diff --git a/docs/src/sidebar/sanfene/network.md b/docs/src/sidebar/sanfene/network.md
index f2478af6e2..a324d75761 100644
--- a/docs/src/sidebar/sanfene/network.md
+++ b/docs/src/sidebar/sanfene/network.md
@@ -2,8 +2,8 @@
title: 计算机网络面试题,63道计算机网络八股文(2.2万字80张手绘图),面渣逆袭必看👍
shortTitle: 面渣逆袭-计算机网络
description: 下载次数超 1 万次,2.2 万字 80 张手绘图,详解 63 道计算机网络面试高频题(让天下没有难背的八股),面渣背会这些计算机网络八股文,这次吊打面试官,我觉得稳了(手动 dog)。
-author: 三分恶&沉默王二
-date: 2025-09-19
+author: 三分恶
+date: 2024-12-01
category:
- 面渣逆袭
tag:
@@ -554,7 +554,7 @@ HTTP/2.0 基于 TCP 协议,而 HTTP/3.0 则基于 QUIC 协议,Quick UDP Conn
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯面经同学 27 云后台技术一面面试原题:HTTP怎么保持长连接呢?
-### 18.🌟说说 HTTP 与 HTTPS 有哪些区别?
+### 18.说说 HTTP 与 HTTPS 有哪些区别?
HTTPS 是 HTTP 的增强版,在 HTTP 的基础上加入了 SSL/TLS 协议,确保数据在传输过程中是加密的。
@@ -568,10 +568,6 @@ HTTP 的默认端⼝号是 80,URL 以`http://`开头;HTTPS 的默认端⼝
> 4. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的得物面经同学 9 面试题目原题:介绍一下http和https的区别?为什么https安全?
> 5. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的同学 30 腾讯音乐面试原题:http 和Https 有啥区别呢?https 安全在哪里
-memo:2025 年 9 月 03 日修改至此,今天[有球友发私信说](https://javabetter.cn/zhishixingqiu/)拿到了京东的正式批 offer,并且业务看上去很核心,那真的要恭喜🎉啊,你付出多少就会有多少的收获,在没有开花结果之前,就是要坚持,鼓励自己。
-
-
-
### 19.为什么要用 HTTPS?
HTTP 是明文传输的,存在数据窃听、数据篡改和身份伪造等问题。而 HTTPS 通过引入 SSL/TLS,解决了这些问题。
@@ -594,10 +590,10 @@ SSL/TLS 在加密过程中涉及到了两种类型的加密方法:
### 20.HTTPS是怎么建立连接的?
-HTTPS 的连接建立在 SSL/TLS 握手之上,其过程可以分为两个阶段:握手阶段和数据传输阶段。
-

+HTTPS 的连接建立在 SSL/TLS 握手之上,其过程可以分为两个阶段:握手阶段和数据传输阶段。
+
①、客户端向服务器发起请求
②、服务器接收到请求后,返回自己的数字证书,包含了公钥、颁发机构等信息。
@@ -658,9 +654,6 @@ HTTPS 通过 SSL/TLS 协议确保了客户端与服务器之间交换的数据
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯面经同学 27 云后台技术一面面试原题:HTTPS怎么建立连接的?HTTPS怎么保证建立的信道是安全的?
> 4. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的虾皮面经同学 13 一面面试原题:https能不能抓包
-memo:2025 年 9 月 20 日修改至此,[今天有球友发喜报](https://javabetter.cn/zhishixingqiu/)说拿到了美的的 offer,虽然不是大厂,但他自己感觉很开心,并且特意感谢了我对他的鼓励。有了保底也可以无所畏惧的继续向前冲了。
-
-
### 21.客户端怎么去校验证书的合法性?
@@ -689,24 +682,7 @@ CA 签发证书的过程是非常严格的:
假如在 HTTPS 的通信过程中,中间人篡改了证书,但由于他没有 CA 机构的私钥,所以无法生成正确的 Signature,因此就无法通过校验。
-#### 如果服务端发送给客户端的加密算法是客户端没有的,这种情况会怎样?
-
-如果客户端不支持服务器建议的任何加密算法,那么安全连接将建立失败。
-
-当客户端向服务器发起一个 HTTPS 请求时,它会发送一个 ClientHello 消息。
-
-
-
-这个消息包含了客户端支持的加密算法列表(称为密码套件),以及其他一些参数。
-
-服务器收到 ClientHello 后,会从客户端提供的密码套件中选择一个它也支持的密码套件,并在 ServerHello 消息中返回给客户端。
-
-
-
-如果服务器无法找到一个双方都支持的密码套件,那么它会发送一个警告消息,表示无法协商出一个共同的加密算法,随后连接将被终止。
-
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的得物面经同学 1 面试原题:HTTPS,中间人伪造证书怎么办,伪造证书机构
-> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动面经同学 34 Java 后端一面面试原题:客户端怎么检验ca证书的合法性
### 22.如何理解 HTTP 协议是无状态的?
@@ -856,14 +832,12 @@ SYN 不仅确保了序列号的同步,使得后续的数据能够有序传输
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动面经同学 9 飞书后端技术一面面试原题:TCP 为什么要三次握手
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的TP联洲同学 5 Java 后端一面的原题:Tcp三次握手,Syn的概念
-### 25.🌟TCP 握手为什么是三次,为什么不能是两次?不能是四次?
+### 25.TCP 握手为什么是三次,为什么不能是两次?不能是四次?
使用三次握手可以建立一个可靠的连接。这一过程的目的是确保双方都知道对方已准备好进行通信,并同步双方的序列号,从而保持数据包的顺序和完整性。
#### 为什么 TCP 握手不能是两次?
----面试中可以不背,但需要理解 start---
-
- 为了防止服务器一直等,等到黄花菜都凉了。
- 为了防止客户端已经失效的连接请求突然又传送到了服务器。
@@ -887,7 +861,7 @@ SYN 不仅确保了序列号的同步,使得后续的数据能够有序传输
但是,过了很久,那封延误的旧邮件突然也到了你朋友那里。如果没有一种机制来识别和处理这种延误的邮件,你的朋友可能会以为这是一个新的连接请求,并尝试响应它,但其实你已经重新发了请求,原来的不需要了。这就导致了不必要的混乱和资源浪费。
----面试中可以不背,但需要理解 end---
+所以我们需要“三次握手”来确认这个过程:
- 第一次握手:客户端发送 SYN 包(连接请求)给服务器,如果这个包延迟了,客户端不会一直等待,它可能会重试并发送一个新的连接请求。
- 第二次握手:服务器收到 SYN 包后,发送一个 SYN-ACK 包(确认接收到连接请求)回客户端。
@@ -977,7 +951,7 @@ SYN Flood 是一种典型的 DDos 攻击,它在短时间内,伪造**不存
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的同学 30 腾讯音乐面试原题:tcp半连接是什么样一个状态?
-### 30.🌟说说 TCP 四次挥手的过程?
+### 30.说说 TCP 四次挥手的过程?
TCP 连接的断开过程被形象地概括为四次挥手。
@@ -1010,7 +984,7 @@ TCP 连接的断开过程被形象地概括为四次挥手。
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯同学 25 后端开发实习一面面试原题:TCP和UDP,TCP连接和断开过程
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动面经同学19番茄小说一面面试原题:TCP断开连接过程
-### 31.🌟TCP 挥手为什么需要四次呢?
+### 31.TCP 挥手为什么需要四次呢?
因为 TCP 是全双工通信协议,数据的发送和接收需要两次一来一回,也就是四次,来确保双方都能正确关闭连接。
@@ -1023,11 +997,6 @@ TCP 连接的断开过程被形象地概括为四次挥手。
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的同学 30 腾讯音乐面试原题:tcp 的挥手为什么是四次,而不是三次呢?
-> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动面经同学34一面面试原题:tcp握手为什么是3次,挥手为什么是4次
-
-memo:2025 年 9 月 04 日修改至此,今天[有球友在星球里提问说](https://javabetter.cn/zhishixingqiu/)拿到了科大讯飞和长鑫存储的 offer,长鑫直接给开奖了,真的速度。
-
-
### 32.TCP 四次挥手过程中,为什么需要等待 2MSL, 才进入 CLOSED 关闭状态?
diff --git a/docs/src/sidebar/sanfene/nixi.md b/docs/src/sidebar/sanfene/nixi.md
index 8b79a4b0a8..63bdc31eef 100644
--- a/docs/src/sidebar/sanfene/nixi.md
+++ b/docs/src/sidebar/sanfene/nixi.md
@@ -12,95 +12,41 @@ head:
content: Java面试题,JavaSE面试题,Java基础面试题,Java集合框架面试题,Java容器面试题,Java虚拟机面试题,JVM面试题,Spring面试题,Redis面试题,MyBatis面试题,MySQL面试题,操作系统面试题,OS面试题,计算机网络面试题,RocketMQ面试题,面试题,八股文,java,springboot,spring,jvm,redis,mybatis,mysql,操作系统,计算机网络,RocketMQ,分布式,微服务,设计模式,Linux
---
-大家好,我是二哥呀,今天给大家隆重介绍一下面渣逆袭 PDF 2.0 版,共有 30 多万字,400+张手绘图,涵盖了 `Java基础`、`Java集合`、`Java并发`、`JVM`、`Spring`、`MyBatis`、`计算机网络`、`操作系统`、`MySQL`、`Redis`、`RocketMQ`、`分布式`、微服务、设计模式、Linux 等 16 个大的主题,可以说是诚意满满。
+大家好,我是二哥呀,今天给大家隆重推荐一下星球嘉宾三分恶的面渣逆袭,一份高质量的面试题八股文,涵盖了`Java基础`、`Java集合`、`Java并发`、`JVM`、`Spring`、`MyBatis`、`计算机网络`、`操作系统`、`MySQL`、`Redis`、`RocketMQ`、`分布式`、微服务、设计模式、Linux 等 16 个大的主题,共有 30 多万字,400+张手绘图,可以说是诚意满满。
-
-
-二哥带背,顺嘴、好背!
-
-先来看一下小红书上吹捧面渣逆袭的,证据 1:
-
-
-
-
-再来看一下牛客上吹捧面渣逆袭的,证据 2:
-
-
-
-
-再来看一下我平常收到的感谢面渣逆袭的私信,证据 3:
-
-
-
-
-真的非常感谢大家的口碑,能活到现在,全靠大家的正反馈啊。
-
-
-
-由于 PDF 没办法自我更新,所以需要最新版的同学,可以微信搜【**沉默王二**】,或者扫描/长按识别下面的二维码,关注二哥的公众号,回复【**222**】即可拉取最新版本。
-
-
-

-
-
-
-百度网盘、阿里云盘、夸克网盘都可以下载到最新版本,我会第一时间更新上去。
-
-
-
-## 持续迭代
-
-第二版的 PDF,我升级了很多内容:
-
-- 对于高频题,会标注在《[Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)》中出现的位置,哪家公司,原题是什么,并且会加🌟,目录一目了然;如果你想节省时间的话,可以优先背诵这些题目,尽快做到知彼知己,百战不殆。
-- 区分八股精华回答版本和原理底层解释,让大家知其然知其所以然,同时又能做到面试时的高效回答。
-- 结合项目([技术派](https://javabetter.cn/zhishixingqiu/paicoding.html)、[pmhub](https://javabetter.cn/zhishixingqiu/pmhub.html)、[派聪明 RAG](https://javabetter.cn/zhishixingqiu/paismart.html))来组织语言,让面试官最大程度感受到你的诚意,而不是机械化的背诵。
-- 修复第一版中出现的问题,包括球友们的私信反馈,网站留言区的评论,以及 [GitHub 仓库](https://github.com/itwanger/toBeBetterJavaer/issues)中的 issue,让这份面试指南更加完善。
-- 增加[二哥编程星球](https://javabetter.cn/zhishixingqiu/)的球友们拿到的一些 offer,对面渣逆袭的感谢,以及对简历修改的一些认可,以此来激励大家,给大家更多信心。
-- 优化排版,增加手绘图,重新组织答案,使其更加口语化,从而更贴近面试官的预期。
-
-## 好评如潮
-
-有球友在做面试官的时候偷偷打开[面渣逆袭网站](https://javabetter.cn/sidebar/sanfene/nixi.html),然后随便挑点问题问。
+有球友在做面试官的时候偷偷打开面渣逆袭,然后随便挑点问题问。

-还有球友[付费加入星球](https://javabetter.cn/zhishixingqiu/)就是为了回馈面渣逆袭给他的帮助,虽然面渣逆袭是开源的、公开的、免费的。但他还是愿意支持二哥,真的很感动,很感动。
+还有球友付费就是为了交面渣逆袭的学费,虽然我不敢说这是市面上最好的八股,但确实对大家应该是有帮助的。

-还有不少同学把[面渣逆袭](https://javabetter.cn/sidebar/sanfene/nixi.html)打印成纸质版,看起来真的非常治愈,封面好看不说,排版也是精美。
+还有读者问怎么付费购买纸质版[面渣逆袭](https://javabetter.cn/sidebar/sanfene/nixi.html),说看到网友有这个,好羡慕啊。说实话,第一眼看到这个封面,真的觉得挺惊艳(虽然是我设计的)。😄

-说真心话,能帮助到大家,能给打印店增加一点收入,我还是挺骄傲的,😄
-
-
-
-## 循序渐进
-
-下面我再针对面渣逆袭的内容进行一个说明。先给大家看看面渣的内容结构:
-
-
-
-每一部分都是循序渐进,由浅入深,看看目录就知道了:
+>下面我将用三弟来代替作者三分恶滴滴,方便行文逻辑。
+## 内容体系全面
-
+话不多说,先给大家看看面渣的内容结构:
+
-
+而且内容不是杂乱无章的,每一部分都是循序渐进,由浅入深,看看目录就知道了:
-
+
+

成体系的知识才是最有价值的,你不仅可以把面渣当做一本面试题解,还可以当作学习指南,带着面渣中的问题,相信你学习起来也会事半功倍。
-## 图文并茂
+## 图文并貌,深入浅出
大家都知道,图比文字更好理解、更好记忆,看过面渣逆袭系列的同学应该都会有这个感受,每个主题经常是三十问、五十图,基本上做到了图比问题多,能用图说话就使劲肝图。
@@ -108,7 +54,7 @@ head:

-也会用一些有意思的比喻去讲解技术,努力让枯燥的知识点变得生动起来。比如,经典的四次挥手,很多同学看完,直呼“满脑子都是分手”:
+三弟还喜欢用一些有意思的比喻去讲解技术,努力让枯燥的知识点变得生动起来。比如,经典的四次挥手,很多同学看完,直呼“满脑子都是分手”:

@@ -124,28 +70,19 @@ head:
这样的例子还有很多,我就不再一一举例了。
-## 在线阅读
+## 持续迭代,不断完善
-考虑到有些同学喜欢在线版,我们也同时上架了 Java 进阶之路网站,记住这个网址:`javabetter.cn`。
+这份八股不是一揽子买卖,而是像一个产品一样,既持续修复 bug、优化体验,又不断迭代新功能。
+二哥也会在此基础上进行优化和更新,包括:
-
+- “迭代新的功能”——分布式、微服务、Dubbo、Elasticsearch、数据结构与算法、系统设计……
+- “修复现有的小 Bug”——随时接受大家的反馈,精益求精,不断打磨内容……
+- “优化用户体验”——优化答案、添加更多图解,后面还会推出突击版。
-Google 搜【面渣逆袭】关键字也行。
+## 在线版阅读
-
-
-
-bing 搜【面渣逆袭】也是排名第一。
-
-
-
-百度 AI 搜【面渣逆袭】也可以。
-
-
-
-
-包括 Java 基础(JavaSE)、Java 集合框架、Java 并发编程(Java 多线程)、Java 虚拟机(JVM)、Spring、MySQL、Redis、MyBatis、操作系统、计算机网络、RocketMQ、分布式、微服务、设计模式、Linux 等等,助你拿到心仪 offer!
+硬核理解版八股文,包括 Java 基础(JavaSE)、Java 集合框架、Java 并发编程(Java 多线程)、Java 虚拟机(JVM)、Spring、MySQL、Redis、MyBatis、操作系统、计算机网络、RocketMQ、分布式、微服务、设计模式等等,助你拿到心仪 offer!
- [面渣逆袭(MySQL 面试题八股文)必看 👍](/sidebar/sanfene/mysql.md)
- [面渣逆袭(Redis 面试题八股文)必看 👍](/sidebar/sanfene/redis.md)
@@ -163,70 +100,73 @@ bing 搜【面渣逆袭】也是排名第一。
- [面渣逆袭(设计模式面试题八股文)必看 👍](/sidebar/sanfene/shejimoshi.md)
- [面渣逆袭(Linux 面试题八股文)必看 👍](/sidebar/sanfene/linux.md)
-## PDF介绍
+## PDF 介绍
有些同学喜欢打印或者阅读 PDF 版本,这里也安排上了。先带大家预览一下:
-1、面渣逆袭Java 基础 PDF 亮白版
+1、Java 基础
-
+
-2、面渣逆袭Java 集合框架/容器epub 版
+2、Java 集合
-
+
-3、面渣逆袭Java 并发编程暗黑版PDF
+3、Java 并发
-
+
-4、面渣逆袭JVM亮白版 PDF
+4、JVM
-
+
-5、面渣逆袭 Spring 亮白版 PDF
+5、Spring
-
+
-6、面渣逆袭MyBatis PDF
+6、MyBatis

-7、面渣逆袭计算机网络PDF
+7、计算机网络

-8、面渣逆袭操作系统PDF
+8、操作系统

-9、面渣逆袭MySQL PDF 2.0 版
+9、MySQL
+
+
-
+10、Redis
-10、面渣逆袭Redis PDF 2.0 版
+
-
+11、RocketMQ
-11、面渣逆袭RocketMQ PDF
+
-
+12、分布式
-12、面渣逆袭分布式 PDF
+
-
+13、微服务
-13、面渣逆袭微服务PDF
+
-
+由于 PDF 没办法自我更新,所以需要最新版的小伙伴,可以微信搜【**沉默王二**】,或者扫描/长按识别下面的二维码,关注二哥的公众号,回复【**222**】即可拉取最新版本。
-由于 PDF 没办法自我更新,所以需要最新版的同学,可以微信搜【**沉默王二**】,或者扫描/长按识别下面的二维码,关注二哥的公众号,回复【**222**】即可拉取最新版本。
+当然了,请允许我的一点点私心,那就是星球的 PDF 版本会比公众号早一个月时间,毕竟星球用户都付费过了,我有必要让他们先享受到一点点福利。相信大家也都能理解,毕竟在线版是免费的,CDN、服务器、域名、OSS 等等都是需要成本的。
+
+更别说我付出的时间和精力了。
-
百度网盘、阿里云盘、夸克网盘都可以下载到最新版本,我会第一时间更新上去。

\ No newline at end of file
diff --git a/docs/src/sidebar/sanfene/redis.md b/docs/src/sidebar/sanfene/redis.md
index b833621224..2da7188b8f 100644
--- a/docs/src/sidebar/sanfene/redis.md
+++ b/docs/src/sidebar/sanfene/redis.md
@@ -3,7 +3,7 @@ title: Redis面试题,57道Redis八股文(4.6万字286张手绘图),面
shortTitle: 面渣逆袭-Redis
description: 下载次数超 1 万次,4.6 万字 286 张手绘图,详解 57 道 Redis 面试高频题(让天下没有难背的八股),面渣背会这些 Redis 八股文,这次吊打面试官,我觉得稳了(手动 dog)。
author: 三分恶
-date: 2025-09-23
+date: 2024-10-31
category:
- 面渣逆袭
tag:
@@ -171,13 +171,6 @@ redis-cli -h slaveof no one
redis-cli -h slaveof
```
-#### 用过哪些缓存数据库,除redis以外?
-
-[技术派实战项目](https://javabetter.cn/zhishixingqiu/paicoding.html)中还用到了 Guava Cache 和 Caffeine 作为本地缓存,Guava Cache 适合小规模缓存,Caffeine 性能更好,支持更多高级特性。
-
-
-
-Caffeine 通常用来作为二级缓存来使用,主要用于存储一些不经常变动的数据,以减轻 Redis 的压力。
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的华为一面原题:说下 Redis 和 HashMap 的区别
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动商业化一面的原题:Redis 和 MySQL 的区别
@@ -193,10 +186,6 @@ Caffeine 通常用来作为二级缓存来使用,主要用于存储一些不
> 12. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的华为 OD 面经同学 1 一面面试原题:Redis 的了解, 部署方案?
> 13. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的同学 30 腾讯音乐面试原题:redis的部署方式都有哪些呢,各自有什么优缺点?
-memo:2025 年 9 月 23 日修改至此,今天[帮球友修改简历](https://javabetter.cn/zhishixingqiu/jianli.html)的时候,收到一位球友的反馈说,从 8.16 加入星球以来,每天都在星球里充电学习,学到了很多东西。对于这种正反馈我是非常开心的。
-
-
-
### 2.Redis 可以用来干什么?
Redis 可以用来做缓存,比如说把高频访问的文章详情、商品信息、用户信息放入 Redis 当中,并通过设置过期时间来保证数据一致性,这样就可以减轻数据库的访问压力。
@@ -258,14 +247,6 @@ String key = "token_bucket:user:123";
Long allowed = (Long) redis.eval(luaScript, 1, key, String.valueOf(capacity), String.valueOf(rate), String.valueOf(now));
```
-#### redis做缓存要考虑哪些问题,在业务方面呢
-
-一类是经典的缓存系统设计问题(穿透、击穿、雪崩),另一类是与业务逻辑紧密相关的业务缓存问题(数据一致性、缓存粒度等)。
-
-当修改了数据库的数据后,如何保证缓存里的数据也同步更新?如果处理不好,用户就会看到“脏数据”。
-
-另外就是我们应该缓存一个完整的、包含各种关联信息的复杂对象,还是只缓存那些最常用的基础字段?
-
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的农业银行面经同学 7 Java 后端面试原题:Redis 相关的基础知识
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动同学 7 Java 后端实习一面的原题:讲一下为什么要用 Redis 去存权限列表?
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动同学 20 测开一面的原题:redis 有什么好处,为什么用 redis
@@ -2483,9 +2464,8 @@ memo:2025 年 5 月 20 日,今天[有球友发贴](https://javabetter.cn/zhi

-具体做法是读取时先查 Redis,未命中再查 MySQL,同时为缓存设置一个合理的过期时间;更新时先更新 MySQL,再删除 Redis。
-这种方式简单有效,适用于读多写少的场景。TTL 过期时间也能够保证即使更新操作失败,未能及时删除缓存,过期时间也能确保数据最终一致。
+具体做法是读取时先查 Redis,未命中再查 MySQL,同时为缓存设置一个合理的过期时间;更新时先更新 MySQL,再删除 Redis。
```java
// 读取逻辑
@@ -2516,6 +2496,8 @@ public void updateUser(UserInfo user) {
}
```
+这种方式简单有效,适用于读多写少的场景。TTL 过期时间也能够保证即使更新操作失败,未能及时删除缓存,过期时间也能确保数据最终一致。
+
#### 那再来说说为什么要删除缓存而不是更新缓存?
最初设计缓存策略时,我也考虑过直接更新缓存,但通过实践发现,删除缓存是更优的选择。
diff --git a/docs/src/sidebar/sanfene/rocketmq.md b/docs/src/sidebar/sanfene/rocketmq.md
index f9030a64c4..5c134eff61 100644
--- a/docs/src/sidebar/sanfene/rocketmq.md
+++ b/docs/src/sidebar/sanfene/rocketmq.md
@@ -3,7 +3,6 @@ title: 消息队列面试题之RocketMQ篇,23道RocketMQ八股文(1.1万字4
shortTitle: 面渣逆袭-RocketMQ
description: 下载次数超 1 万次,1.1 万字 45 张手绘图,详解 23 道 RocketMQ 面试高频题(让天下没有难背的八股),面渣背会这些 RocketMQ 八股文,这次吊打面试官,我觉得稳了(手动 dog)。
author: 三分恶
-date: 2025-09-24
category:
- 面渣逆袭
tag:
@@ -14,209 +13,73 @@ head:
content: RocketMQ面试题,RocketMQ,面试题,八股文
---
-
-
-## 前言
-
1.1 万字 45 张手绘图,详解 23 道 RocketMQ 面试高频题(让天下没有难背的八股),面渣背会这些 RocketMQ 八股文,这次吊打面试官,我觉得稳了(手动 dog)。整理:沉默王二,戳[转载链接](https://mp.weixin.qq.com/s/N6wq52pBGh8xkS-5uRcO2g),作者:三分恶,戳[原文链接](https://mp.weixin.qq.com/s/IvBt3tB_IWZgPjKv5WGS4A)。
-亮白版本更适合拿出来打印,这也是很多学生党喜欢的方式,打印出来背诵的效率会更高。
-
-
-
-2025 年 11 月 02 日开始着手第二版更新。
-
-- 对于高频题,会标注在《[Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)》中出现的位置,哪家公司,原题是什么,并且会加🌟,目录一目了然;如果你想节省时间的话,可以优先背诵这些题目,尽快做到知彼知己,百战不殆。
-- 区分八股精华回答版本和原理底层解释,让大家知其然知其所以然,同时又能做到面试时的高效回答。
-- 结合项目([Spring Boot+React 前后端分离 web 项目技术派](https://javabetter.cn/zhishixingqiu/paicoding.html)、[微服务pmhub](https://javabetter.cn/zhishixingqiu/pmhub.html)、[RAG 项目派聪明AI 知识库](https://javabetter.cn/zhishixingqiu/paismart.html))来组织语言,让面试官最大程度感受到你的诚意,而不是机械化的背诵。
-- 修复第一版中出现的问题,包括球友们的私信反馈,网站留言区的评论,以及 [GitHub 仓库](https://github.com/itwanger/toBeBetterJavaer/issues)中的 issue,让这份面试指南更加完善。
-- 增加[二哥编程星球](https://javabetter.cn/zhishixingqiu/)的球友们拿到的一些 offer,对面渣逆袭的感谢,以及对简历修改的一些认可,以此来激励大家,给大家更多信心。
-- 优化排版,增加手绘图,重新组织答案,使其更加口语化,从而更贴近面试官的预期。
-
-
-
-由于 PDF 没办法自我更新,所以需要最新版的小伙伴,可以微信搜【**沉默王二**】,或者扫描/长按识别下面的二维码,关注二哥的公众号,回复【**222**】即可拉取最新版本。
-
-
-

-
-
-当然了,请允许我的一点点私心,那就是星球的 PDF 版本会比公众号早一个月时间,毕竟星球用户都付费过了,我有必要让他们先享受到一点点福利。相信大家也都能理解,毕竟在线版是免费的,CDN、服务器、域名、OSS 等等都是需要成本的。
-
-更别说我付出的时间和精力了,大家觉得有帮助还请给个口碑,让你身边的同事、同学都能受益到。
-
-
-
-我把二哥的 Java 进阶之路、JVM 进阶之路、并发编程进阶之路,以及所有面渣逆袭的版本都放进来了,涵盖 Java基础、Java集合、Java并发、JVM、Spring、MyBatis、计算机网络、操作系统、MySQL、Redis、RocketMQ、分布式、微服务、设计模式、Linux 等 16 个大的主题,共有 40 多万字,2000+张手绘图,可以说是诚意满满。
-
-展示一下暗黑版本的 PDF 吧,排版清晰,字体优雅,更加适合夜服,晚上看会更舒服一点。
-
-
-
-
-
## 基础
### 1.为什么要使用消息队列呢?
-我认为消息队列的核心价值主要体现在四个方面。首先是解耦,这是最重要的。
+消息队列(Message Queue, MQ)是一种非常重要的中间件技术,广泛应用于分布式系统中,以提高系统的可用性、解耦能力和异步通信效率。
-
+①、**解耦**
-比如在[派聪明 RAG 项目](https://javabetter.cn/zhishixingqiu/paismart.html)中,文件上传完成之后,会有很多后续的任务,比如提取元数据、生成全文索引、做 AI 向量化处理。
+生产者将消息放入队列,消费者从队列中取出消息,这样一来,生产者和消费者之间就不需要直接通信,生产者只管生产消息,消费者只管消费消息,这样就实现了解耦。
-这些处理不仅数据量大,而且任务本身也比较消耗资源,没有消息队列的话,文件上传服务就得等这些任务都处理完才能返回结果给用户,体验会很差。
-
-
-
-于是我们引入了 Kafka 来做消息队列,文件上传服务只需要把文件处理任务发送到消息队列里就可以结束了。其他服务各自去消费这条消息,独立处理自己的业务逻辑。这样即使某个服务宕机了,也不会影响文件上传的核心流程,系统的容错能力就大大提升了。
+
-再比如书在 [PmHub](https://javabetter.cn/zhishixingqiu/pmhub.html) 中,任务审批就用了 RocketMQ 来做解耦。
+像 [PmHub](https://javabetter.cn/zhishixingqiu/pmhub.html) 中的任务审批,就用了 RocketMQ 来做解耦。

-其次是异步处理,系统可以将那些耗时的任务放在消息队列中异步处理,从而快速响应用户的请求。比如说,用户下单后,系统可以先返回一个下单成功的消息,然后将订单信息放入消息队列中,后台系统再去处理订单信息。
+②、**异步**:
+
+系统可以将那些耗时的任务放在消息队列中异步处理,从而快速响应用户的请求。比如说,用户下单后,系统可以先返回一个下单成功的消息,然后将订单信息放入消息队列中,后台系统再去处理订单信息。

-再有就是削峰填谷,这一点在高并发场景下特别重要。比如秒杀活动,瞬间可能来了几十万个请求。如果直接打到数据库,系统肯定会崩溃。但通过消息队列,所有请求先进队列,后端消费者按照自己的处理能力逐个消费,即使暂时处理不过来,消息也能安全地存储在队列里。这样系统就不会被突发流量打倒。
+③、**削峰**:
-
+削峰填谷是一种常见的技术手段,用于应对系统高并发请求的瞬时流量高峰,通过消息队列,可以将瞬时的高峰流量转化为持续的低流量,从而保护系统不会因为瞬时的高流量而崩溃。
-除此之外,消息队列还支持持久化存储,支持消息重试和事务机制。这样即使消费者在处理消息时出现异常,消息也不会丢失,可以重新投递处理,最终保证业务逻辑一定会被正确执行。
+
#### 如何用RocketMQ做削峰填谷的?
-我的理解是:用户的所有请求不直接打到后端服务,而是先发送到 RocketMQ 的消息队列里。RocketMQ 作为一个高吞吐量的中间件,能够快速接收这些请求。然后消费者端根据自己的处理能力,按照一定的速度从队列里拉取消息进行处理。这样就形成了一个缓冲区,能够吸收掉突发的流量。
+用户请求到达系统后,由生产者接收请求并将其转化为消息,发送到 RocketMQ 队列中。队列用来充当缓冲区,将大量请求按照顺序排队,这样就可以削减请求高峰时对后端服务的直接压力。
-就拿秒杀场景来举例吧。首先,用户的秒杀请求不是直接去扣减库存,而是先发一条消息到 RocketMQ。这个操作很快,因为只是把消息丢到队列里,不涉及任何业务逻辑处理。然后在消费端,我们启动一个消费者线程,这些消费者以一个相对稳定的速度去消费消息,一条一条地处理秒杀逻辑,比如检查库存、扣库存、生成订单等。
+不仅如此,生产者通过异步方式发送消息,还可以快速响应用户请求。
-```java
-// 生产者端 - 接收秒杀请求
-@PostMapping("/seckill")
-public Result seckill(Long productId, Long userId) {
- // 直接发送消息到 RocketMQ,快速返回
- Message message = new Message("seckill_topic",
- JSON.toJSONString(new SeckillRequest(productId, userId)).getBytes());
-
- try {
- SendResult sendResult = rocketMQTemplate.syncSend("seckill_topic", message);
- return Result.success("秒杀请求已提交,请稍候");
- } catch (Exception e) {
- return Result.fail("系统繁忙,请稍后重试");
- }
-}
+消费者从 RocketMQ 队列中按照一定速率读取消息并进行处理。可以根据后端处理能力和当前负载情况动态调整消费者的消费速率,达到填谷的效果。
-// 消费者端 - 按照自己的能力消费消息
-@RocketMQMessageListener(topic = "seckill_topic",
- consumerGroup = "seckill_consumer_group")
-public class SeckillConsumer implements RocketMQListener {
-
- @Override
- public void onMessage(SeckillRequest request) {
- // 这里按照相对稳定的速度处理秒杀逻辑
- // 消费者能处理多快就处理多快,不会被突发流量冲击
- seckillService.processSeckill(request.getProductId(), request.getUserId());
- }
-}
-```
-
-这里有一个需要注意的地方,就是消息堆积的问题,如果消费者一直跟不上生产速度,消息会无限堆积,可能最终会导致磁盘满或者消息过期被删除。所以在实际项目中,我们需要监控队列的堆积情况,必要时通过增加消费者或优化消费逻辑来加快处理速度。
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动同学 7 Java 后端实习一面的原题:有了解过 MQ 吗?
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯面经同学 24 面试原题:如何用消息队列做削峰填谷的?
> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的美团面经同学 4 一面面试原题:项目里用 RocketMQ 做削峰,还有什么场景适合消息队列
> 4. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动同学 20 测开一面的原题:RocketMQ有什么用,你一般拿来做什么
-memo:2025 年 11 月 03 日修改至此,今天有[球友反馈说深信服开奖了](https://javabetter.cn/zhishixingqiu/),AI 软开能到 30k+,真的已经非常高了,赶超互联网大厂的 SSP。AI 软开岗位,未来几年会非常吃香,大家可以重点关注一下,球友用的就是 [PmHub](https://javabetter.cn/zhishixingqiu/pmhub.html)+RAG 项目。
-
-
-
### 2.为什么要选择 RocketMQ?
-首先,在事务支持方面,RocketMQ 做得特别好。比如说在转账场景下,我们要保证"扣款"的本地事务和"发送转账消息"这两个操作要么都成功,要么都失败,不能出现只扣款但没发消息的情况。RocketMQ 的事务消息机制就能很好地解决这个问题。
-
-```java
-// RocketMQ 事务消息示例
-TransactionSendResult sendResult = rocketMQTemplate.executeAndReplyTransaction(
- "transfer_topic",
- new Message("transfer_topic",
- JSON.toJSONString(new TransferRequest(fromId, toId, amount)).getBytes()),
- new RocketMQLocalTransactionListener() {
- @Override
- public RocketMQLocalTransactionState executeLocalTransaction(Message msg, Object arg) {
- try {
- // 执行本地事务 - 扣款
- accountService.deductAccount(fromId, amount);
- return RocketMQLocalTransactionState.COMMIT;
- } catch (Exception e) {
- return RocketMQLocalTransactionState.ROLLBACK;
- }
- }
-
- @Override
- public RocketMQLocalTransactionState checkLocalTransaction(Message msg) {
- // 事务回查逻辑
- return accountService.isDeducted(fromId, amount) ?
- RocketMQLocalTransactionState.COMMIT :
- RocketMQLocalTransactionState.ROLLBACK;
- }
- }
-);
-```
-
-其次是对顺序消息的支持。在很多场景下,消息的顺序很重要。比如订单的生命周期,应该是:下单 → 支付 → 发货 → 确认收货。如果消息乱序了,就会出现还没付款就发货的逻辑混乱。
-
-RocketMQ 的顺序消息能够保证同一个 OrderId 的消息,它们能够被发送到同一个队列,然后被同一个消费者按顺序消费。
-
-[PmHub](https://javabetter.cn/zhishixingqiu/pmhub.html) 中的任务审批流程,就是用的 RocketMQ 来保证审批步骤的正确顺序。
+
-
-
-再有就是 RocketMQ 支持 Master-Slave 模式的高可用部署。当 Master 节点宕机时,Slave 可以自动转换为 Master,从而提供更好的容错能力。
-
-
-
-如果是日志收集和流式处理场景,Kafka 更合适,因为它天生为大数据场景设计。[派聪明 RAG 项目](https://javabetter.cn/zhishixingqiu/paismart.html)中的文件上传后的向量化、索引构建任务,就是用的 Kafka 来做消息队列。
-
-
-
-
-如果是需要轻量级的消息传递,RabbitMQ 更好,因为它实现了 AMQP 协议,支持丰富的路由和交换机类型。
-
-[技术派项目](https://javabetter.cn/zhishixingqiu/paicoding.html)中的点赞、收藏、评论等功能的异步处理,就是用的 RabbitMQ 来做消息队列。
-
-
+我们系统主要面向 C 端用户,有一定的并发量,对性能也有比较高的要求,所以选择了低延迟、吞吐量比较高,可用性比较好的 RocketMQ。
### 3.RocketMQ 有什么优缺点?
-首先是支持事务消息,这是 RocketMQ 最大的亮点。我的理解是,RocketMQ 通过两阶段提交的方式,保证了消息发送和本地事务的原子性。这对于需要保证数据一致性的场景特别重要。比如库存扣减和订单创建,要么两个都成功,要么都回滚,不能出现不一致的状态。
-
-其次是支持顺序消息。对于同一个业务主体(比如同一个订单),RocketMQ 能保证消息的有序性。这个设计特别巧妙,通过 ShardingKey 将消息路由到同一个队列,然后再由同一个消费者线程顺序消费。这解决了很多实际业务的需求。
+RocketMQ 优点:
-再有就是高吞吐量和低延迟。RocketMQ 的单机吞吐能达到几十万 TPS。
+- 单机吞吐量:十万级
+- 可用性:非常高,分布式架构
+- 消息可靠性:经过参数优化配置,消息可以做到 0 丢失
+- 功能支持:MQ 功能较为完善,还是分布式的,扩展性好
+- 支持 10 亿级别的消息堆积,不会因为堆积导致性能下降
+- 源码是 Java,方便结合公司自己的业务二次开发
+- 天生为金融互联网领域而生,对于可靠性要求很高的场景,尤其是电商里面的订单扣款,以及业务削峰,在大量交易涌入时,后端可能无法及时处理的情况
+- **RoketMQ**在稳定性上可能更值得信赖,这些业务场景在阿里双 11 已经经历了多次考验,如果你的业务有上述并发场景,建议可以选择**RocketMQ**
-缺点方面,由于 RocketMQ 的消息去重不是自动的,所以需要消费者端自己实现幂等,否则容易出现重复消费的问题。
+RocketMQ 缺点:
-```java
-// 需要在消费端自己实现幂等
-@RocketMQMessageListener(topic = "order_topic",
- consumerGroup = "order_consumer_group")
-public class OrderConsumer implements RocketMQListener {
-
- @Override
- public void onMessage(OrderMessage message) {
- // 需要根据消息的唯一标识检查是否已经处理过
- if (orderService.isProcessed(message.getOrderId())) {
- // 已经处理过,直接返回
- return;
- }
-
- // 处理订单逻辑
- orderService.processOrder(message);
- }
-}
-```
+- 支持的客户端语言不多,目前是 Java 及 c++,其中 c++不成熟
+- 没有在 MQ 核心中去实现**JMS**等接口,有些系统要迁移需要修改大量代码
#### 说说你对 RocketMQ 的理解?
@@ -226,214 +89,152 @@ RocketMQ 是阿里巴巴开源的一款分布式消息中间件,具有高吞
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的京东同学 4 云实习面试原题:说说你对RocketMQ的理解
-memo:2025 年 11 月 4 日修改至此,今天有球友刚好面到了星球嘉宾的公司,三个项目,mydb+[技术派](https://javabetter.cn/zhishixingqiu/paicoding.html)+[派聪明](https://javabetter.cn/zhishixingqiu/paismart.html),这下也是稳稳拿下了。
-
-
-
### 4.消息队列有哪些消息模型?
-我认为消息队列的消息模型可以分为两大类:点对点模型和发布-订阅模型。
+消息队列有两种模型:**队列模型**和**发布/订阅模型**。
-点对点模型的特点是一条消息只能被一个消费者消费。生产者把消息发送到一个队列里,消费者从这个队列里拉取消息进行处理。一旦消息被某个消费者消费了,这条消息就被删除了,其他消费者是看不到这条消息的。
+- **队列模型**
-
+这是最初的一种消息队列模型,对应着消息队列“发-存-收”的模型。生产者往某个队列里面发送消息,一个队列可以存储多个生产者的消息,一个队列也可以有多个消费者,但是消费者之间是竞争关系,也就是说每条消息只能被一个消费者消费。
-发布-订阅模型的特点是一条消息可以被多个订阅者消费。生产者发布消息到一个主题(Topic),所有订阅了这个主题的消费者都会收到这条消息。
+
-
+- **发布/订阅模型**
-这个模型特别适合用来做事件通知。比如说在[技术派项目](https://javabetter.cn/zhishixingqiu/paicoding.html)中,作者发布了一篇内容,可以同时通知所有关注了这个作者的用户,让他们收到更新提醒。系统级的消息通知也是类似的道理。
+如果需要将一份消息数据分发给多个消费者,并且每个消费者都要求收到全量的消息。很显然,队列模型无法满足这个需求。解决的方式就是发布/订阅模型。
-
+在发布 - 订阅模型中,消息的发送方称为发布者(Publisher),消息的接收方称为订阅者(Subscriber),服务端存放消息的容器称为主题(Topic)。发布者将消息发送到主题中,订阅者在接收消息之前需要先“订阅主题”。“订阅”在这里既是一个动作,同时还可以认为是主题在消费时的一个逻辑副本,每份订阅中,订阅者都可以接收到主题的所有消息。
-### 5.那 RocketMQ 的消息模型呢?
+
-RocketMQ 采用的是一个统一的、基于 Topic 和 Group 的消息模型。同一个消费者组内可以算是点对点,不同消费者组之间算是发布-订阅。
+它和 “队列模式” 的异同:生产者就是发布者,队列就是主题,消费者就是订阅者,无本质区别。唯一的不同点在于:一份消息数据是否可以被多次消费。
-
-
-在 RocketMQ 中,主题(Topic)是消息的逻辑分类。生产者把消息发送到某个 Topic,消费者从某个 Topic 拉取消息。一个 Topic 可以有多个生产者向它发送消息,也可以有多个消费者从它消费消息。
-
-一个 Topic 在物理上被分成了多个队列(Queue)。生产者发送消息时,消息会根据某个 key 被路由到不同的 Queue 中。这个设计的巧妙之处在于,它既保证了单个 Queue 内的消息顺序,又能通过多个 Queue 实现并行处理。
-
-
+### 5.那 RocketMQ 的消息模型呢?
-消费者端,消费者归属于某一个消费者组(Consumer Group)。一个 消费者组内的多个消费者会协同消费同一个主题的消息。RocketMQ 会把主题下的多个队列分配给这个消费者组内的消费者进行消费。
+RocketMQ 使用的消息模型是标准的发布-订阅模型,在 RocketMQ 的术语表中,生产者、消费者和主题,与发布-订阅模型中的概念是完全一样的。
-```
-场景 1:一个消费者,一个 Topic 有 4 个 Queue
+RocketMQ 本身的消息是由下面几部分组成:
-ConsumerGroup: order_consumer_group
- └─ Consumer 1
- ├─ Queue 0
- ├─ Queue 1
- ├─ Queue 2
- └─ Queue 3
+
-一个消费者消费所有 4 个队列。
-```
+- **Message**
-```
-场景 2:两个消费者,一个 Topic 有 4 个 Queue
-
-ConsumerGroup: order_consumer_group
- ├─ Consumer 1
- │ ├─ Queue 0
- │ └─ Queue 2
- │
- └─ Consumer 2
- ├─ Queue 1
- └─ Queue 3
-
-两个消费者各消费 2 个队列,实现了负载均衡。
-```
+**Message**(消息)就是要传输的信息。
-```
-场景 3:四个消费者,一个 Topic 有 4 个 Queue
+一条消息必须有一个主题(Topic),主题可以看做是你的信件要邮寄的地址。
-ConsumerGroup: order_consumer_group
- ├─ Consumer 1 → Queue 0
- ├─ Consumer 2 → Queue 1
- ├─ Consumer 3 → Queue 2
- └─ Consumer 4 → Queue 3
+一条消息也可以拥有一个可选的标签(Tag)和额处的键值对,它们可以用于设置一个业务 Key 并在 Broker 上查找此消息以便在开发期间查找问题。
-四个消费者各消费 1 个队列,充分并行。
-```
+- **Topic**
-memo:2025 年 11 月 15 日修改至此,今天有球友发喜报说携程开了 SP,非常满意,感谢星球里的项目,他用的是[派聪明RAG](https://javabetter.cn/zhishixingqiu/paismart.html)+mydb 轮子。
+**Topic**(主题)可以看做消息的归类,它是消息的第一级类型。比如一个电商系统可以分为:交易消息、物流消息等,一条消息必须有一个 Topic 。
-
+**Topic** 与生产者和消费者的关系非常松散,一个 Topic 可以有 0 个、1 个、多个生产者向其发送消息,一个生产者也可以同时向不同的 Topic 发送消息。
-### 6.消息的消费模式了解吗?
+一个 Topic 也可以被 0 个、1 个、多个消费者订阅。
-我认为消费模式可以从两个维度来分类:一个是消费的方向,一个是消费的范围。
+- **Tag**
-从消费方向来分的话,有两种模式,一种是 pull 模式,一种是 push 模式。
+**Tag**(标签)可以看作子主题,它是消息的第二级类型,用于为用户提供额外的灵活性。使用标签,同一业务模块不同目的的消息就可以用相同 Topic 而不同的 **Tag** 来标识。比如交易消息又可以分为:交易创建消息、交易完成消息等,一条消息可以没有 **Tag** 。
-
+标签有助于保持你的代码干净和连贯,并且还可以为 **RocketMQ** 提供的查询系统提供帮助。
-pull 模式需要消费者主动去消息队列中拉取消息,消费者可以控制拉取的速度、数量,但需要不断地轮询,比较浪费资源。
+- **Group**
-push 模式则是消息队列主动把消息推送给消费者,消费者只需要注册一个监听器,消息一到达就触发回调进行处理,响应速度快,但可能会出现消息堆积的情况。
+RocketMQ 中,订阅者的概念是通过消费组(Consumer Group)来体现的。每个消费组都消费主题中一份完整的消息,不同消费组之间消费进度彼此不受影响,也就是说,一条消息被 Consumer Group1 消费过,也会再给 Consumer Group2 消费。
-从消费范围来分的话,也有两种模式,一种是集群消费,一种是广播消费。
+消费组中包含多个消费者,同一个组内的消费者是竞争消费的关系,每个消费者负责消费组内的一部分消息。默认情况,如果一条消息被消费者 Consumer1 消费了,那同组的其他消费者就不会再收到这条消息。
-
+- **Message Queue**
-集群消费是指,同一个消费者组中的多个消费者共同消费一个主题中的消息。消息被分散分配给这个消费者组中的各个消费者,每条消息只被这个消费者组中的一个消费者消费。
+**Message Queue**(消息队列),一个 Topic 下可以设置多个消息队列,Topic 包括多个 Message Queue ,如果一个 Consumer 需要获取 Topic 下所有的消息,就要遍历所有的 Message Queue。
-换句话说,RocketMQ 会把主题下的所有队列均匀地分配给消费者组内的消费者,实现负载均衡。这样也能保证同一条消息只会被消费者组内的一个消费者消费,避免重复消费。
+RocketMQ 还有一些其它的 Queue——例如 ConsumerQueue。
-```
-Topic: order_topic
- ├─ Queue 0 → [消息1] [消息3] [消息5]
- ├─ Queue 1 → [消息2] [消息4] [消息6]
- ├─ Queue 2 → [消息7] [消息9] [消息11]
- └─ Queue 3 → [消息8] [消息10] [消息12]
-
-ConsumerGroup: order_consumer_group
- ├─ Consumer 1 消费 Queue 0, 1
- ├─ Consumer 2 消费 Queue 2, 3
-
-同一条消息只被 Consumer 1 或 Consumer 2 之一消费,不会重复消费。
-```
+- **Offset**
-广播消费是指,同一个主题的每条消息都会被消费者组内的每个消费者消费一次。也就是说,消费者组内的每个消费者都会收到主题下的所有消息,从而实现消息的广播效果。
+在 Topic 的消费过程中,由于消息需要被不同的组进行多次消费,所以消费完的消息并不会立即被删除,这就需要 RocketMQ 为每个消费组在每个队列上维护一个消费位置(Consumer Offset),这个位置之前的消息都被消费过,之后的消息都没有被消费过,每成功消费一条消息,消费位置就加一。
-```
-Topic: config_update_topic
- └─ [配置更新消息1] [配置更新消息2] [配置更新消息3]
-
-ConsumerGroup: config_consumer_group
- ├─ Consumer 1(服务器1上的应用)
- │ └─ 收到:消息1, 消息2, 消息3(完整的)
- │
- ├─ Consumer 2(服务器2上的应用)
- │ └─ 收到:消息1, 消息2, 消息3(完整的)
- │
- └─ Consumer 3(服务器3上的应用)
- └─ 收到:消息1, 消息2, 消息3(完整的)
-
-三个消费者都收到了所有的消息,各自独立处理。
-```
+也可以这么说,`Queue` 是一个长度无限的数组,**Offset** 就是下标。
-### 7.RocketMQ 的基本架构了解吗?
+RocketMQ 的消息模型中,这些就是比较关键的概念了。画张图总结一下:
-RocketMQ 的架构由四个核心部分组成:NameServer、Broker、生产者和消费者。
+
-
+### 6.消息的消费模式了解吗?
-我的理解是,NameServer 就是 RocketMQ 的路由中心,负责维护 Topic 和 Broker 之间的路由信息。生产者在发送消息前,消费者在消费消息前,都会先从 NameServer 获取最新的路由信息。
+消息消费模式有两种:**Clustering**(集群消费)和**Broadcasting**(广播消费)。
-- 每个 Broker 会向 NameServer 注册自己的信息,包括 Broker 的地址、端口、存储的 Topic 和 Queue 等。
-- NameServer 会根据 Topic 名称告诉生产者和消费者对应的 Broker 地址。
-- Broker 会定期向 NameServer 发送心跳,报告自己的状态。
+
-
+默认情况下就是集群消费,这种模式下`一个消费者组共同消费一个主题的多个队列,一个队列只会被一个消费者消费`,如果某个消费者挂掉,分组内其它消费者会接替挂掉的消费者继续消费。
-Broker 是消息存储中心,它的职责包括:
+而广播消费消息会发给消费者组中的每一个消费者进行消费。
-- 所有生产者发送的消息都会被存储在 Broker 上,以文件的形式持久化到磁盘。
-- 消费者从 Broker 拉取消息时,Broker 需要根据消费者的 Offset 找到对应的消息,返回给消费者。
-- 如果配置了高可用,Broker Master 会把消息同步到 Broker Slave,实现主从备份。
+### 7.RoctetMQ 基本架构了解吗?
-生产者在发送消息时,会先从 NameServer 获取 Topic 的路由信息,然后根据路由信息把消息发送到对应的 Broker 上。
+先看图,RocketMQ 的基本架构:
-消费者在消费消息时,也会先从 NameServer 获取 Topic 的路由信息,然后根据路由信息从对应的 Broker 上拉取消息进行处理。
+
-memo:2025 年 11 月 25 日修改至此,今天有[球友反馈说](https://javabetter.cn/zhishixingqiu/)拿到了科大讯飞和华为的 offer,都开奖了,秋招算是告一段落。她特意感谢了[技术派](https://javabetter.cn/zhishixingqiu/paicoding.html)让她找到暑期实习,秋招靠[派聪明 RAG](https://javabetter.cn/zhishixingqiu/paismart.html)和星球的实习搭子稳稳拿下。还有[我改的简历给她的招聘](https://javabetter.cn/zhishixingqiu/jianli.html)加了不少分,线下被夸了无数次。
+RocketMQ 一共有四个部分组成:NameServer,Broker,Producer 生产者,Consumer 消费者,它们对应了:发现、发、存、收,为了保证高可用,一般每一部分都是集群部署的。
-
+### 8.那能介绍一下这四部分吗?
-### 8.能详细介绍一下RocketMQ的NameServer吗?
+类比一下我们生活的邮政系统——
-NameServer 是一个路由中心和服务发现中心。他的第一个职责是存储和维护路由信息。当 Broker 启动时,会向 NameServer 注册自己的信息。
+邮政系统要正常运行,离不开下面这四个角色, 一是发信者,二 是收信者, 三是负责暂存传输的邮局, 四是负责协调各个地方邮局的管理机构。对应到 RocketMQ 中,这四个角色就是 Producer、 Consumer、 Broker 、NameServer。
-
+
-NameServer 把这些信息存储在内存里,形成一个路由表。
+##### NameServer
-
+NameServer 是一个无状态的服务器,角色类似于 Kafka 使用的 Zookeeper,但比 Zookeeper 更轻量。
-它的第二个职责是提供路由查询服务。当生产者或消费者需要知道某个主题在哪个 Broker 上时,就向 NameServer 查询。NameServer 会根据主题名称返回对应的 Broker 地址和队列信息。
+特点:
-第三个职责是监控 Broker 的状态。Broker 会定期向 NameServer 发送心跳,报告自己的状态。如果某个 Broker 长时间没有发送心跳,NameServer 会将其标记为不可用,并从路由表中移除。
+- 每个 NameServer 结点之间是相互独立,彼此没有任何信息交互。
+- Nameserver 被设计成几乎是无状态的,通过部署多个结点来标识自己是一个伪集群,Producer 在发送消息前从 NameServer 中获取 Topic 的路由信息也就是发往哪个 Broker,Consumer 也会定时从 NameServer 获取 Topic 的路由信息,Broker 在启动时会向 NameServer 注册,并定时进行心跳连接,且定时同步维护的 Topic 到 NameServer。
-#### 请说说Broker的作用?
+功能主要有两个:
-Broker 是一个消息存储服务器,它负责接收生产者的消息,并将其存储起来,然后在消费者拉取时返回给它们。
+- 1、和 Broker 结点保持长连接。
+- 2、维护 Topic 的路由信息。
-
+##### Broker
-#### 请说说生产者?
+消息存储和中转角色,负责存储和转发消息。
-生产者的核心职责是把应用程序的数据转化为消息,发送到 Broker。
+- Broker 内部维护着一个个 Consumer Queue,用来存储消息的索引,真正存储消息的地方是 CommitLog(日志文件)。
-
+
-RocketMQ 提供了三种方式发送消息:同步、异步和单向。
+- 单个 Broker 与所有的 Nameserver 保持着长连接和心跳,并会定时将 Topic 信息同步到 NameServer,和 NameServer 的通信底层是通过 Netty 实现的。
-- **同步发送**:生产者发送消息后会阻塞等待 Broker 的响应。只有收到 Broker 确认消息已存储的响应后,才会返回给应用程序。
-- **异步发送**:生产者发送消息后立即返回,不阻塞。Broker 的响应会通过回调函数返回给应用程序。
-- **单向发送**:生产者发送消息后直接返回,不等待响应,也不需要回调。这个模式用于一些不关心发送结果的场景。
+##### Producer
-#### 请说说消费者?
+消息生产者,业务端负责发送消息,由用户自行实现和分布式部署。
-消费者是消息的接收方,它的核心职责就是从 Broker 拉取消息,进行业务处理,然后提交消费位移。
+- **Producer**由用户进行分布式部署,消息由**Producer**通过多种负载均衡模式发送到**Broker**集群,发送低延时,支持快速失败。
+- **RocketMQ** 提供了三种方式发送消息:同步、异步和单向
-
+- **同步发送**:同步发送指消息发送方发出数据后会在收到接收方发回响应之后才发下一个数据包。一般用于重要通知消息,例如重要通知邮件、营销短信。
+- **异步发送**:异步发送指发送方发出数据后,不等接收方发回响应,接着发送下个数据包,一般用于可能链路耗时较长而对响应时间敏感的业务场景,例如用户视频上传后通知启动转码服务。
+- **单向发送**:单向发送是指只负责发送消息而不等待服务器回应且没有回调函数触发,适用于某些耗时非常短但对可靠性要求并不高的场景,例如日志收集。
-RocketMQ 同时支持 Pull、Push、Pop 三种消费模型。
+##### Consumer
-Pull 模型是最基础的消费方式。消费者主动向 Broker 发起请求,拉取消息。Push 模型在使用上看起来像是服务端在推送消息,但实际上底层仍然是 Pull 模型。
+消息消费者,负责消费消息,一般是后台系统负责异步消费。
-当消费者很多的时候,消费重平衡会消耗很长的时间,于是 RocketMQ 提供了 Pop 模型。Pop 模型把消费重平衡完全移到了服务端,以减轻消费者的负担。
+- **Consumer**也由用户部署,支持 PUSH 和 PULL 两种消费模式,支持**集群消费**和**广播消费**,提供**实时的消息订阅机制**。
+- **Pull**:拉取型消费者(Pull Consumer)主动从消息服务器拉取信息,只要批量拉取到消息,用户应用就会启动消费过程,所以 Pull 称为主动消费型。
+- **Push**:推送型消费者(Push Consumer)封装了消息的拉取、消费进度和其他的内部维护工作,将消息到达时执行的回调接口留给用户应用程序来实现。所以 Push 称为被动消费类型,但其实从实现上看还是从消息服务器中拉取消息,不同于 Pull 的是 Push 首先要注册消费监听器,当监听器处触发后才开始消费消息。
-
+GitHub 上标星 10000+ 的开源知识库《[二哥的 Java 进阶之路](https://github.com/itwanger/toBeBetterJavaer)》第一版 PDF 终于来了!包括 Java 基础语法、数组&字符串、OOP、集合框架、Java IO、异常处理、Java 新特性、网络编程、NIO、并发编程、JVM 等等,共计 32 万余字,500+张手绘图,可以说是通俗易懂、风趣幽默……详情戳:[太赞了,GitHub 上标星 10000+ 的 Java 教程](https://javabetter.cn/overview/)
-memo:2025 年 11 月 27 日修改至此,今天有球友反馈说拿到了字节的 offer,SSP offer,还有 8 万签字费,特意感谢了[星球的项目](https://javabetter.cn/zhishixingqiu/)和[面渣逆袭八股](https://javabetter.cn/sidebar/sanfene/nixi.html)。
+微信搜 **沉默王二** 或扫描下方二维码关注二哥的原创公众号沉默王二,回复 **222** 即可免费领取。
-
+
## 进阶
@@ -613,43 +414,28 @@ long id = IdUtil.getSnowflakeNextId();
### 12.顺序消息如何实现?
-RocketMQ 提供了两种级别的顺序消息:全局顺序和局部顺序。
+RocketMQ 实现顺序消息的关键在于保证消息生产和消费过程中严格的顺序控制,即确保同一业务的消息按顺序发送到同一个队列中,并由同一个消费者线程按顺序消费。

-全局顺序是指整个 Topic 的所有消息都严格按照发送顺序消费,这种方式性能比较低,实际项目中用得不多。
-
+#### 局部顺序消息如何实现?
-局部顺序是指特定分区内的消息保证顺序,这是我们常用的方式。
+局部顺序消息保证在某个逻辑分区或业务逻辑下的消息顺序,例如同一个订单或用户的消息按顺序消费,而不同订单或用户之间的顺序不做保证。

-要保证顺序,关键是要把需要保证顺序的消息发送到同一个 MessageQueue 中。
+#### 全局顺序消息如何实现?
-```java
-// 根据订单ID选择队列,保证同一订单的消息在同一队列
-producer.send(message, new MessageQueueSelector() {
- @Override
- public MessageQueue select(List mqs, Message msg, Object arg) {
- String orderId = (String) arg;
- int index = orderId.hashCode() % mqs.size();
- return mqs.get(index);
- }
-}, orderId);
-```
+全局顺序消息保证消息在整个系统范围内的严格顺序,即消息按照生产的顺序被消费。
+
+可以将所有消息发送到一个单独的队列中,确保所有消息按生产顺序发送和消费。
-每个 MessageQueue 在 Broker 中对应一个 ConsumeQueue,消息按照到达 Broker 的顺序依次写入。
+
-当消费者开始消费某个 MessageQueue 时,会在 Broker 端对该队列加锁,其他消费者就无法同时消费这个队列。这样确保了同一时间只有一个消费者在处理某个队列的消息,从而保证了消费顺序。
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的京东面经同学 2 后端面试原题:说说mq原理,怎么保证消息接受顺序?
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的收钱吧面经同学 1 Java 后端一面面试原题:RocketMQ的顺序消息?
-> 3. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的中小厂面经同学6 广州中厂面试原题:RocketMQ怎么保证消息顺序?
-
-memo:2025 年 8 月 15 日修改至此,今天在[帮球友修改简历时](https://javabetter.cn/zhishixingqiu/jianli.html),收到这样一个反馈:目前正在高德暑期实习,3 月底找二哥修改过简历,觉得改的非常好。
-
-
### 13.如何实现消息过滤?
diff --git a/docs/src/sidebar/sanfene/shejimoshi.md b/docs/src/sidebar/sanfene/shejimoshi.md
index 265f815deb..3a08fb3f88 100644
--- a/docs/src/sidebar/sanfene/shejimoshi.md
+++ b/docs/src/sidebar/sanfene/shejimoshi.md
@@ -2,7 +2,7 @@
title: 设计模式面试题,5道设计模式八股文(3000字10张手绘图),面渣逆袭必看👍
shortTitle: 面渣逆袭-设计模式
description: 下载次数超 1 万次,3000 字 10 张手绘图,详解 5 道 设计模式 面试高频题(让天下没有难背的八股),面渣背会这些 设计模式 八股文,这次吊打面试官,我觉得稳了(手动 dog)。
-date: 2025-09-20
+date: 2024-11-08
author: 沉默王二
category:
- 面渣逆袭
@@ -267,49 +267,8 @@ public class FactoryMethodPatternDemo {
1. **数据库访问层(DAL)组件**:工厂方法模式适用于数据库访问层,其中需要根据不同的数据库(如MySQL、PostgreSQL、Oracle)创建不同的数据库连接。工厂方法可以隐藏这些实例化逻辑,只提供一个统一的接口来获取数据库连接。
2. **日志记录**:当应用程序需要实现多种日志记录方式(如向文件记录、数据库记录或远程服务记录)时,可以使用工厂模式来设计一个灵活的日志系统,根据配置或环境动态决定具体使用哪种日志记录方式。
-### 线程不是有线程名吗,怎么做到让线程的前缀名统一,通过factory来实现?
-
-可以通过工厂模式创建线程,并在工厂方法中设置线程的前缀名。这样可以确保所有通过工厂创建的线程都具有统一的命名规范。
-
-```java
-class NamedThreadFactory implements ThreadFactory {
- private final String prefix;
- private int count = 0;
-
- public NamedThreadFactory(String prefix) {
- this.prefix = prefix;
- }
-
- @Override
- public Thread newThread(Runnable r) {
- Thread thread = new Thread(r);
- thread.setName(prefix + "-" + count++);
- return thread;
- }
-}
-
-public class ThreadFactoryDemo {
- public static void main(String[] args) {
- ThreadFactory factory = new NamedThreadFactory("MyThread");
-
- Runnable task = () -> {
- System.out.println("线程名称: " + Thread.currentThread().getName());
- };
-
- for (int i = 0; i < 5; i++) {
- Thread thread = factory.newThread(task);
- thread.start();
- }
- }
-}
-```
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的华为一面原题:说下工厂模式,场景
-> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的字节跳动面经同学 34 Java 后端技术一面面试原题:工厂模式了解吗?
-
-memo:2025 年 9 月 20 日修改至此,今天球友在面快手的时候,被问了很多[派聪明 RAG 项目](https://javabetter.cn/zhishixingqiu/paismart.html)的题目,说面试官对这个项目非常感兴趣。再次感谢球友的口碑。
-
-
## 03、什么是单例模式?
@@ -391,6 +350,8 @@ class Singleton {
当 instance 创建后,再次调用 getInstance 方法时,不会进入同步代码块,从而提高了性能。
+
+
#### ④、静态内部类如何实现单例?
利用 Java 的[静态内部类](https://javabetter.cn/oo/static.html)(Static Nested Class)和[类加载机制](https://javabetter.cn/jvm/class-load.html)来实现线程安全的延迟初始化。
@@ -432,11 +393,6 @@ public enum Singleton {
单例模式有 5 种实现方式,常见的有饿汉式、懒汉式、双重检查锁定、静态内部类和枚举。
-### synchronized加到代码块上和方法上有什么区别?
-
-将 synchronized 加到方法上时,锁定的是整个方法,任何线程在调用该方法时都会获得该对象的锁,直到方法执行完毕才释放锁。
-
-将 synchronized 加到代码块上 `synchronized (Singleton.class)`时,锁定的是类的 Class 对象,所有对这个类的 synchronized 代码块都会串行执行。
> 1. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的华为一面原题:说下单例模式,有几种
> 2. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的腾讯面经同学 22 暑期实习一面面试原题:单例模式的好处
@@ -446,13 +402,9 @@ public enum Singleton {
> 6. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的携程面经同学 10 Java 暑期实习一面面试原题:单例模式,如何线程安全
> 7. [Java 面试指南(付费)](https://javabetter.cn/zhishixingqiu/mianshi.html)收录的同学 D 小米一面原题:单例模式有几种
-memo:2025 年 8 月 12 日修改至此,今天有球友在VIP 群里讲,他师兄的简历一眼[技术派](https://javabetter.cn/zhishixingqiu/paicoding.html),🤣,看来这个项目的口碑是真不错。
-
-
-
## 04、了解哪些设计模式?
-单例模式、策略模式。
+单例模式、策略模式和工厂模式。
在需要控制资源访问,如配置管理、连接池管理时经常使用单例模式。它确保了全局只有一个实例,并提供了一个全局访问点。
@@ -464,185 +416,6 @@ memo:2025 年 8 月 12 日修改至此,今天有球友在VIP 群里讲,他
后面想添加新的 AI 服务,只需要增加一个新的策略类,不需要修改原有代码,这样就提高了代码的可扩展性。
-### 你想做一个导出的数据导出的功能,然后他可能导出的格式有Excel、有JSON,可能有XML,然后如果你用面向对象这些方法去做,会怎么去设计这个实现?
-
-我会使用策略模式+工厂模式来实现。
-
-首先,我会定义一个导出接口 `DataExporter`,该接口包含一个导出方法 `export(data)`,用于导出数据。
-
-```java
-public interface DataExporter {
- void export(List