Skip to content

Commit

Permalink
doc: 修改图片外链
Browse files Browse the repository at this point in the history
  • Loading branch information
01Petard committed Nov 7, 2024
1 parent a78db36 commit f22fd92
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 43 deletions.
4 changes: 2 additions & 2 deletions docs/开发/My Java Guide/My Java Guide - JVM.md
Original file line number Diff line number Diff line change
Expand Up @@ -428,11 +428,11 @@ Java内存模型(`JMM`,Java Memory Model)主要关注的是线程之间如
> 在JDK1.2版之后提供了WeakReference类来实现弱引用,弱引用主要在ThreadLocal中使用。弱引|用对象本身也可以使用引|用队列进行回收。
- ***虚引用:*无法获取包含的对象。唯一用途是当对象被回收时,可以接收到对应的通知,知道对象被回收了。**
- ***虚引用:无法获取包含的对象。唯一用途是当对象被回收时,可以接收到对应的通知,知道对象被回收了。**
> Java中使用PhantomReference实现了虚引用,使用虚引用实现了直接内存中为了及时知道直接内存对象不再使用,从而回收内存。
- ***终结器引用:*对象回收时可以自救,不建议使用。(在对象需要被回收时,对象将会被放置在Finalizer类中的引用队列中,并在稍后由一条由FinalizerThread线程从队列中获取对象,然后执行对象的finalize方法(再将自身对象使用强引用关联上))**
- **终结器引用:对象回收时可以自救,不建议使用。(在对象需要被回收时,对象将会被放置在Finalizer类中的引用队列中,并在稍后由一条由FinalizerThread线程从队列中获取对象,然后执行对象的finalize方法(再将自身对象使用强引用关联上))**
- **可达性分析法**:
Expand Down
70 changes: 39 additions & 31 deletions docs/开发/My Java Guide/My Java Guide - Java基础.md
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
```

## 例:超时关闭不付款的订单
Expand Down Expand Up @@ -2477,11 +2477,11 @@ Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种
- **`CyclicBarrier`**:可以让一组线程互相等待,直到到达某个公共屏障点
- **`Semaphore`**:信号量,可以控制对特定资源的访问线程数
- **`volatile`**Java 中的关键字,确保变量的可见性,防止指令重排
- **`AtomicInteger`**可以用于实现线程安全的计数器或其他共享变量。
- **`AtomicInteger`**可以用于实现线程安全的计数器或其他共享变量。

补充 Object 中的方法说明:

- **Objectsynchronized **——wait()、notify()、notifyAll():使线程进入等待状态,释放锁。唤醒单个等待线程。唤醒所有等待线程。
- **Objectsynchronized**——wait()、notify()、notifyAll():使线程进入等待状态,释放锁。唤醒单个等待线程。唤醒所有等待线程。
- **LockCondition**——await()、signal():使持有ReentranLock锁的线程等待。唤醒持有ReentranLock锁的线程。
- **BlockingQueue**——put()、take():将元素放入阻塞队列。从队列中获取取元素

Expand Down Expand Up @@ -2808,19 +2808,27 @@ workQueue - 当没有空闲核心线程时,新来任务会加入到此队列

- **`FixedThreadPool`**:固定线程数量的线程池,可控制线程最大并发数,超出的线程会在队列中等待,**允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM**

<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202405131641783.png" alt="image-20240513164118730" style="zoom: 80%;float:left;"/>
<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202405131641783.png" alt="image-20240513164118730" style="zoom: 80%;"/>



- **`SingleThreadExecutor`**:单线程化的线程池,保证所有任务按照指定顺序执行,**允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM**

<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202405131641155.png" alt="image-20240513164133123" style="zoom: 80%;float:left;"/>
<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202405131641155.png" alt="image-20240513164133123" style="zoom: 80%;"/>



- **`CachedThreadPool`**:可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程,**允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM**

<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202405131646303.png" alt="image-20240513164601273" style="zoom: 80%;float:left;"/>
<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202405131646303.png" alt="image-20240513164601273" style="zoom: 80%;"/>



- **`ScheduledThreadPool`**:可以执行延迟任务的线程池,支持定时及周期性任务执行

<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202405131641651.png" alt="image-20240513164158611" style="zoom: 80%;float:left;"/>
<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202405131641651.png" alt="image-20240513164158611" style="zoom: 80%;"/>



- **`WorkStealingPool`**:基于任务窃取算法的线程池。线程池中的每个线程维护一个双端队列(deque),线程可以从自己的队列中取任务执行。如果线程的任务队列为空,它可以从其他线程的队列中"窃取"任务来执行,达到负载均衡的效果。适合大量小任务并行执行,特别是递归算法或大任务分解成小任务的场景。

Expand Down Expand Up @@ -2888,7 +2896,7 @@ public void execute(Runnable command) {

## 底层原理:线程池的动态调整是如何保证线程安全的?

**1. 使用 `volatile` 修饰 核心线程数 和 最大线程数 **
**1. 使用 `volatile` 修饰 核心线程数 和 最大线程数**

核心线程数`corePoolSize` 和最大线程数 `maximumPoolSize` 都是用 `volatile` 修饰的,保证了当这些字段被修改时,其他线程能够看到最新的值,而且不会发生指令重排序,确保了多线程环境下的可见性和有序性。

Expand Down
4 changes: 2 additions & 2 deletions docs/开发/My Java Guide/My Java Guide - Spring.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ Bean不一定是线程安全的。

**循环依赖**:有多个类被Spring管理,它们在实例化时互相持有对方,最终形成闭环。

<img src="https://pic.code-nav.cn/mianshiya/question_picture/1772087337535152129/VagJkJyh_658dafbb-f354-41e0-97e9-896759a20c94_mianshiya.png" alt="img" style="zoom:100%;" />
<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202411071640490.png" alt="img" style="zoom:100%;" />

示例代码:

Expand Down Expand Up @@ -403,7 +403,7 @@ Spring为单例搞的三个 map,也就是三级依赖:

步骤 2 中如果查询发现 Bean 还未创建,就直接返回 null,返回 null 之后,说明这个 Bean 还未创建,这个时候会标记这个 Bean 正在创建中,然后再调用 `createBean` 来创建 Bean,而实际创建是调用方法 `doCreateBean`。doCreateBean 这个方法就会执行上面我们说的三步骤:实例化、属性注入初始化。在实例化 Bean 之后,**会往 三级缓存(singletonFactories)塞入一个工厂,而调用这个工厂的 `getObject` 方法,就能得到这个 Bean**

<img src="https://pic.code-nav.cn/mianshiya/question_picture/1815995005551374337/SU9AOSuc_image-20240911195840657_mianshiya.png" alt="image-20240911195840657.png" style="zoom:85%;" />
<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202411071641321.png" alt="image-20240911195840657.png" style="zoom:85%;" />

# IOC

Expand Down
16 changes: 8 additions & 8 deletions docs/开发/My Java Guide/My Java Guide - 分布式.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ Raft算法将节点分为三种状态:**跟随者(Follower)、候选人(
说到这就可以停下了,然后等面试官发问,正常情况下他会选一个点进行深入探讨,这时候我们只能见招拆招了。
<img src="https://pic.code-nav.cn/mianshiya/question_picture/1772087337535152129/QZcneqlN_dc72f0b0-c32d-4902-82f8-b72a968f7eee_mianshiya.png" alt="img" style="zoom:100%;float:left;" />
<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202411071757171.png" alt="img" style="zoom:100%;" />
## 细节:动态代理 / RPC的实现原理
Expand All @@ -177,13 +177,13 @@ RPC 会给接口生成一个代理类,我们调用这个接口实际调用的
动态代理中,最常见的技术就是 Spring AOP 了,涉及的有 JDK 动态代理和 cglib。
<img src="https://pic.code-nav.cn/mianshiya/question_picture/1772087337535152129/0lDq7g3W_e6a5195e-0fcd-4229-820f-8013c3bcb341_mianshiya.png" alt="img" style="zoom:100%;float:left;" />
<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202411071757686.png" alt="img" style="zoom:100%;" />
## 细节:序列化
**序列化原因:**网络传输的数据是“扁平”的,最终需要转化成“扁平”的二进制数据在网络中传输。
**序列化方案:**有很多序列化选择,一般需要**综合考虑通用性、性能、可读性和兼容性**
**序列化方案:**有很多序列化选择,一般需要综合考虑通用性、性能、可读性和兼容性。
**序列化方案对比:**
Expand All @@ -208,11 +208,11 @@ RPC 会给接口生成一个代理类,我们调用这个接口实际调用的
例如Dubbo 协议:
<img src="https://pic.code-nav.cn/mianshiya/question_picture/1772087337535152129/mYyU0BI5_7c3ca8fb-65c9-45ac-aae6-7739ff58ee52_mianshiya.png" alt="img" style="zoom:120%;float:left;" />
<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202411071758085.png" alt="img" style="zoom:120%;" />
## 细节:网络传输
<img src="https://pic.code-nav.cn/mianshiya/question_picture/1772087337535152129/LuV0WzRQ_bc1e2b9d-2d0c-442f-aa06-6b94f0ed64cf_mianshiya.png" alt="img" style="zoom:90%;float:left;" />
<img src="https://cdn.jsdelivr.net/gh/01Petard/imageURL@main/img/202411071758623.png" alt="img" style="zoom:90%;" />
一般而言用的都是 **IO 多路复用**,因为大部分 RPC 调用场景都是高并发调用,IO 复用可以利用较少的线程 hold 住很多请求。
Expand Down Expand Up @@ -715,22 +715,22 @@ 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的基础上增加了预表决阶段,以减少阻塞情况的发生。

1. **预表决阶段**:协调者向参与者发送预表决请求。
2. **准备阶段**:参与者回复预表决结果。
3. **提交阶段**:根据参与者回复的结果,协调者发送提交或回滚指令。

**3. 单边提交(One-Sided Commit) ** **【AP系统、DDD架构】**
**3. 单边提交(One-Sided Commit)【AP系统、DDD架构】**

在这种方案中,参与者独立决定是否提交事务,而不需要等待协调者的指示。

Expand Down

0 comments on commit f22fd92

Please sign in to comment.