From f22fd9229f5fb07e25750230b82ce411778efc20 Mon Sep 17 00:00:00 2001
From: 01Petard <1520394133@qq.com>
Date: Thu, 7 Nov 2024 20:13:57 +0800
Subject: [PATCH] =?UTF-8?q?doc:=20=E4=BF=AE=E6=94=B9=E5=9B=BE=E7=89=87?=
=?UTF-8?q?=E5=A4=96=E9=93=BE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../My Java Guide/My Java Guide - JVM.md" | 4 +-
...a Guide - Java\345\237\272\347\241\200.md" | 70 +++++++++++--------
.../My Java Guide/My Java Guide - Spring.md" | 4 +-
...- \345\210\206\345\270\203\345\274\217.md" | 16 ++---
4 files changed, 51 insertions(+), 43 deletions(-)
diff --git "a/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - JVM.md" "b/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - JVM.md"
index da14b59..0a4d06b 100644
--- "a/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - JVM.md"
+++ "b/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - JVM.md"
@@ -428,11 +428,11 @@ Java内存模型(`JMM`,Java Memory Model)主要关注的是线程之间如
> 在JDK1.2版之后提供了WeakReference类来实现弱引用,弱引用主要在ThreadLocal中使用。弱引|用对象本身也可以使用引|用队列进行回收。
- - ***虚引用:*无法获取包含的对象。唯一用途是当对象被回收时,可以接收到对应的通知,知道对象被回收了。**
+ - ***虚引用:无法获取包含的对象。唯一用途是当对象被回收时,可以接收到对应的通知,知道对象被回收了。**
> Java中使用PhantomReference实现了虚引用,使用虚引用实现了直接内存中为了及时知道直接内存对象不再使用,从而回收内存。
- - ***终结器引用:*对象回收时可以自救,不建议使用。(在对象需要被回收时,对象将会被放置在Finalizer类中的引用队列中,并在稍后由一条由FinalizerThread线程从队列中获取对象,然后执行对象的finalize方法(再将自身对象使用强引用关联上))**
+ - **终结器引用:对象回收时可以自救,不建议使用。(在对象需要被回收时,对象将会被放置在Finalizer类中的引用队列中,并在稍后由一条由FinalizerThread线程从队列中获取对象,然后执行对象的finalize方法(再将自身对象使用强引用关联上))**
- **可达性分析法**:
diff --git "a/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - Java\345\237\272\347\241\200.md" "b/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - Java\345\237\272\347\241\200.md"
index 71a3846..cc57505 100644
--- "a/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - Java\345\237\272\347\241\200.md"
+++ "b/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - Java\345\237\272\347\241\200.md"
@@ -2118,31 +2118,31 @@ Timer 可以实现延时任务,也可以实现周期性任务。
因为使用线程池进行任务调度,所以不会因某个任务的异常终止而导致其他任务停止。并且它提供了更灵活的 API,可以更精细地控制任务的执行周期和策略。
```java
- public static void main(String[] args) {
- ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
-
- // 延迟3秒后执行任务
- executor.schedule(
- () -> System.out.println("Task running... "),
- 3,
- TimeUnit.SECONDS);
-
- // 初始延迟1秒后开始执行任务,之后每2秒执行一次
- executor.scheduleAtFixedRate(
- () -> System.out.println("Task executed at " + System.currentTimeMillis()), // Runnable
- 1, // initialDelay
- 2, // period
- TimeUnit.SECONDS);
-
- // 模拟长时间运行,实际应用中应该有一个条件来决定何时关闭线程池
- try {
- Thread.sleep(10000); // 让主线程等待10秒
- // 关闭线程池
- executor.shutdown();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+public static void main(String[] args) {
+ ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
+
+ // 延迟3秒后执行任务
+ executor.schedule(
+ () -> System.out.println("Task running... "),
+ 3,
+ TimeUnit.SECONDS);
+
+ // 初始延迟1秒后开始执行任务,之后每2秒执行一次
+ executor.scheduleAtFixedRate(
+ () -> System.out.println("Task executed at " + System.currentTimeMillis()), // Runnable
+ 1, // initialDelay
+ 2, // period
+ TimeUnit.SECONDS);
+
+ // 模拟长时间运行,实际应用中应该有一个条件来决定何时关闭线程池
+ try {
+ Thread.sleep(10000); // 让主线程等待10秒
+ // 关闭线程池
+ executor.shutdown();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
}
+}
```
## 例:超时关闭不付款的订单
@@ -2477,11 +2477,11 @@ Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种
- **`CyclicBarrier`**:可以让一组线程互相等待,直到到达某个公共屏障点
- **`Semaphore`**:信号量,可以控制对特定资源的访问线程数
- **`volatile`**:Java 中的关键字,确保变量的可见性,防止指令重排
-- **`AtomicInteger`**,可以用于实现线程安全的计数器或其他共享变量。
+- **`AtomicInteger`**:可以用于实现线程安全的计数器或其他共享变量。
补充 Object 中的方法说明:
-- **Object 和 synchronized **——wait()、notify()、notifyAll():使线程进入等待状态,释放锁。唤醒单个等待线程。唤醒所有等待线程。
+- **Object 和 synchronized**——wait()、notify()、notifyAll():使线程进入等待状态,释放锁。唤醒单个等待线程。唤醒所有等待线程。
- **Lock 和 Condition**——await()、signal():使持有ReentranLock锁的线程等待。唤醒持有ReentranLock锁的线程。
- **BlockingQueue**——put()、take():将元素放入阻塞队列。从队列中获取取元素
@@ -2808,19 +2808,27 @@ workQueue - 当没有空闲核心线程时,新来任务会加入到此队列
- **`FixedThreadPool`**:固定线程数量的线程池,可控制线程最大并发数,超出的线程会在队列中等待,**允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM**
-
+
+
+
- **`SingleThreadExecutor`**:单线程化的线程池,保证所有任务按照指定顺序执行,**允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM**
-
+
+
+
- **`CachedThreadPool`**:可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程,**允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM**
-
+
+
+
- **`ScheduledThreadPool`**:可以执行延迟任务的线程池,支持定时及周期性任务执行
-
+
+
+
- **`WorkStealingPool`**:基于任务窃取算法的线程池。线程池中的每个线程维护一个双端队列(deque),线程可以从自己的队列中取任务执行。如果线程的任务队列为空,它可以从其他线程的队列中"窃取"任务来执行,达到负载均衡的效果。适合大量小任务并行执行,特别是递归算法或大任务分解成小任务的场景。
@@ -2888,7 +2896,7 @@ public void execute(Runnable command) {
## 底层原理:线程池的动态调整是如何保证线程安全的?
-**1. 使用 `volatile` 修饰 核心线程数 和 最大线程数 **
+**1. 使用 `volatile` 修饰 核心线程数 和 最大线程数**
核心线程数`corePoolSize` 和最大线程数 `maximumPoolSize` 都是用 `volatile` 修饰的,保证了当这些字段被修改时,其他线程能够看到最新的值,而且不会发生指令重排序,确保了多线程环境下的可见性和有序性。
diff --git "a/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - Spring.md" "b/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - Spring.md"
index b26deaa..6224742 100644
--- "a/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - Spring.md"
+++ "b/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - Spring.md"
@@ -332,7 +332,7 @@ Bean不一定是线程安全的。
**循环依赖**:有多个类被Spring管理,它们在实例化时互相持有对方,最终形成闭环。
-
+
示例代码:
@@ -403,7 +403,7 @@ Spring为单例搞的三个 map,也就是三级依赖:
步骤 2 中如果查询发现 Bean 还未创建,就直接返回 null,返回 null 之后,说明这个 Bean 还未创建,这个时候会标记这个 Bean 正在创建中,然后再调用 `createBean` 来创建 Bean,而实际创建是调用方法 `doCreateBean`。doCreateBean 这个方法就会执行上面我们说的三步骤:实例化、属性注入初始化。在实例化 Bean 之后,**会往 三级缓存(singletonFactories)塞入一个工厂,而调用这个工厂的 `getObject` 方法,就能得到这个 Bean**。
-
+
# IOC
diff --git "a/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - \345\210\206\345\270\203\345\274\217.md" "b/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - \345\210\206\345\270\203\345\274\217.md"
index cd64a92..c9ba6f2 100644
--- "a/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - \345\210\206\345\270\203\345\274\217.md"
+++ "b/docs/\345\274\200\345\217\221/My Java Guide/My Java Guide - \345\210\206\345\270\203\345\274\217.md"
@@ -159,7 +159,7 @@ Raft算法将节点分为三种状态:**跟随者(Follower)、候选人(
说到这就可以停下了,然后等面试官发问,正常情况下他会选一个点进行深入探讨,这时候我们只能见招拆招了。
-
+
## 细节:动态代理 / RPC的实现原理
@@ -177,13 +177,13 @@ RPC 会给接口生成一个代理类,我们调用这个接口实际调用的
动态代理中,最常见的技术就是 Spring AOP 了,涉及的有 JDK 动态代理和 cglib。
-
+
## 细节:序列化
**序列化原因:**网络传输的数据是“扁平”的,最终需要转化成“扁平”的二进制数据在网络中传输。
-**序列化方案:**有很多序列化选择,一般需要**综合考虑通用性、性能、可读性和兼容性**。
+**序列化方案:**有很多序列化选择,一般需要综合考虑通用性、性能、可读性和兼容性。
**序列化方案对比:**
@@ -208,11 +208,11 @@ RPC 会给接口生成一个代理类,我们调用这个接口实际调用的
例如Dubbo 协议:
-
+
## 细节:网络传输
-
+
一般而言用的都是 **IO 多路复用**,因为大部分 RPC 调用场景都是高并发调用,IO 复用可以利用较少的线程 hold 住很多请求。
@@ -715,14 +715,14 @@ public class SlidingWindowLimiter {
为了确保分布式事务的ACID,有以下常见的分布式事务解决方案:
-**1. 两阶段提交(Two-Phase Commit, 2PC)** **【XA 协议、Atomikos、Bitronix】**
+**1. 两阶段提交(Two-Phase Commit, 2PC)【XA 协议、Atomikos、Bitronix】**
最传统的分布式事务协议之一。包括准备阶段和提交阶段,其中协调者与参与者进行交互以决定是否提交或回滚事务。
1. **准备阶段**:协调者询问所有参与者是否准备好提交事务。
2. **提交阶段**:如果所有参与者都同意,则协调者命令所有参与者提交;如果任何一个参与者不同意,则协调者命令所有参与者回滚。
-**2. 三阶段提交(Three-Phase Commit, 3PC) ** **【SAGA、TCC(Try-Confirm-Cancel)、最终一致性】**
+**2. 三阶段提交(Three-Phase Commit, 3PC)【SAGA、TCC(Try-Confirm-Cancel)、最终一致性】**
3PC是在2PC的基础上增加了预表决阶段,以减少阻塞情况的发生。
@@ -730,7 +730,7 @@ public class SlidingWindowLimiter {
2. **准备阶段**:参与者回复预表决结果。
3. **提交阶段**:根据参与者回复的结果,协调者发送提交或回滚指令。
-**3. 单边提交(One-Sided Commit) ** **【AP系统、DDD架构】**
+**3. 单边提交(One-Sided Commit)【AP系统、DDD架构】**
在这种方案中,参与者独立决定是否提交事务,而不需要等待协调者的指示。