1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-16 18:10:13 +08:00

[docs update]java并发部分内容重构完善

This commit is contained in:
guide 2022-08-12 19:03:57 +08:00
parent f535bc7e9e
commit 075593b231
14 changed files with 63 additions and 31 deletions

View File

@ -342,7 +342,7 @@ Dubbo 是一款国产的 RPC 框架,由阿里开源。相关阅读:
消息队列在分布式系统中主要是为了解耦和削峰。相关阅读: [消息队列常见问题总结](docs/high-performance/message-queue/message-queue.md)。 消息队列在分布式系统中主要是为了解耦和削峰。相关阅读: [消息队列常见问题总结](docs/high-performance/message-queue/message-queue.md)。
1. **RabbitMQ** : [RabbitMQ 基础知识总结](docs/high-performance/message-queue/rabbitmq-intro.md)、[RabbitMQ 常见面试题](docs/high-performance/message-queue/rabbitmq-questions.md) 1. **RabbitMQ** : [RabbitMQ 基础知识总结](docs/high-performance/message-queue/rabbitmq-intro.md)、[RabbitMQ 常见面试题](docs/high-performance/message-queue/rabbitmq-questions.md)
2. **RocketMQ** : [RocketMQ 基础知识总结](docs/high-performance/message-queue/rocketmq-intro)、[RocketMQ 常见面试题总结](docs/high-performance/message-queue/rocketmq-questions.md) 2. **RocketMQ** : [RocketMQ 基础知识总结](docs/high-performance/message-queue/rocketmq-intro.md)、[RocketMQ 常见面试题总结](docs/high-performance/message-queue/rocketmq-questions.md)
3. **Kafka** [Kafka 常见问题总结](docs/high-performance/message-queue/kafka-questions-01.md) 3. **Kafka** [Kafka 常见问题总结](docs/high-performance/message-queue/kafka-questions-01.md)
### 读写分离&分库分表 ### 读写分离&分库分表

View File

@ -61,7 +61,7 @@ head:
### try-catch-finally 如何使用? ### try-catch-finally 如何使用?
- `try` 用于捕获异常。其后可接零个或多个 `catch` 块,如果没有 `catch` 块,则必须跟一个 `finally` 块。 - `try` 用于捕获异常。其后可接零个或多个 `catch` 块,如果没有 `catch` 块,则必须跟一个 `finally` 块。
- \*`catch` 用于处理 try 捕获到的异常。 - `catch` 用于处理 try 捕获到的异常。
- `finally` 无论是否捕获或处理异常,`finally` 块里的语句都会被执行。当在 `try` 块或 `catch` 块中遇到 `return` 语句时,`finally` 语句块将在方法返回之前被执行。 - `finally` 无论是否捕获或处理异常,`finally` 块里的语句都会被执行。当在 `try` 块或 `catch` 块中遇到 `return` 语句时,`finally` 语句块将在方法返回之前被执行。
代码示例: 代码示例:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

View File

@ -20,7 +20,7 @@ head:
在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程。 在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程。
如下图所示,在 windows 中通过查看任务管理器的方式,我们就可以清楚看到 window 当前运行的进程(.exe 文件的运行)。 如下图所示,在 Windows 中通过查看任务管理器的方式,我们就可以清楚看到 Windows 当前运行的进程(`.exe` 文件的运行)。
![进程示例图片-Windows](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/进程示例图片-Windows.png) ![进程示例图片-Windows](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/进程示例图片-Windows.png)
@ -28,7 +28,7 @@ head:
线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享进程的**堆**和**方法区**资源,但每个线程有自己的**程序计数器**、**虚拟机栈**和**本地方法栈**,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。 线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享进程的**堆**和**方法区**资源,但每个线程有自己的**程序计数器**、**虚拟机栈**和**本地方法栈**,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
Java 程序天生就是多线程程序,我们可以通过 JMX 来看一下一个普通的 Java 程序有哪些线程,代码如下。 Java 程序天生就是多线程程序,我们可以通过 JMX 来看一个普通的 Java 程序有哪些线程,代码如下。
```java ```java
public class MultiThread { public class MultiThread {
@ -59,13 +59,13 @@ public class MultiThread {
## 请简要描述线程与进程的关系,区别及优缺点? ## 请简要描述线程与进程的关系,区别及优缺点?
**从 JVM 角度说进程和线程之间的关系** 从 JVM 角度说进程和线程之间的关系。
### 图解进程和线程的关系 ### 图解进程和线程的关系
下图是 Java 内存区域,通过下图我们从 JVM 的角度来说一下线程和进程之间的关系。 下图是 Java 内存区域,通过下图我们从 JVM 的角度来说一下线程和进程之间的关系。
![](../jvm/pictures/java内存区域/Java运行时数据区域JDK1.8.png) ![Java 运行时数据区域JDK1.8 之后)](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/java/jvm/java-runtime-data-areas-jdk1.8.png)
从上图可以看出:一个进程中可以有多个线程,多个线程共享进程的**堆**和**方法区 (JDK1.8 之后的元空间)**资源,但是每个线程有自己的**程序计数器**、**虚拟机栈** 和 **本地方法栈** 从上图可以看出:一个进程中可以有多个线程,多个线程共享进程的**堆**和**方法区 (JDK1.8 之后的元空间)**资源,但是每个线程有自己的**程序计数器**、**虚拟机栈** 和 **本地方法栈**
@ -97,11 +97,18 @@ public class MultiThread {
堆和方法区是所有线程共享的资源,其中堆是进程中最大的一块内存,主要用于存放新创建的对象 (几乎所有对象都在这里分配内存),方法区主要用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 堆和方法区是所有线程共享的资源,其中堆是进程中最大的一块内存,主要用于存放新创建的对象 (几乎所有对象都在这里分配内存),方法区主要用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
## 说说并发与并行的区别? ## 并发与并行的区别
- **并发**:两个及两个以上的作业在同一 **时间段** 内执行。 - **并发**:两个及两个以上的作业在同一 **时间段** 内执行。
- **并行**:两个及两个以上的作业在同一 **时刻** 执行。 - **并行**:两个及两个以上的作业在同一 **时刻** 执行。
最关键的点是:是否是 **同时** 执行。
## 同步和异步的区别
- **同步** 发出一个调用之后,在没有得到结果之前, 该调用就不可以返回,一直等待。
- **异步** :调用在发出之后,不用等待返回结果,该调用直接返回。
## 为什么要使用多线程呢? ## 为什么要使用多线程呢?
先从总体上来说: 先从总体上来说:
@ -120,33 +127,42 @@ public class MultiThread {
## 说说线程的生命周期和状态? ## 说说线程的生命周期和状态?
Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态图源《Java 并发编程艺术》4.1.4 节)。 Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态
![Java 线程的状态 ](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/19-1-29/Java%E7%BA%BF%E7%A8%8B%E7%9A%84%E7%8A%B6%E6%80%81.png) - NEW: 初始状态,线程被创建出来但没有被调用 `start()`
- RUNNABLE: 运行状态,线程被调用了 `start()`等待运行的状态。
- BLOCKED :阻塞状态,需要等待锁释放。
- WAITING等待状态表示该线程需要等待其他线程做出一些特定动作通知或中断
- TIME_WAITING超时等待状态可以在指定的时间后自行返回而不是像 WAITING 那样一直等待。
- TERMINATED终止状态表示该线程已经运行完毕。
线程在生命周期中并不是固定处于某一个状态而是随着代码的执行在不同状态之间切换。Java 线程状态变迁如下图所示(图源 [issue#736](https://github.com/Snailclimb/JavaGuide/issues/736) 线程在生命周期中并不是固定处于某一个状态而是随着代码的执行在不同状态之间切换。
![](./images/interview-questions/java-life-cycle.png) Java 线程状态变迁图(图源:[挑错 |《Java 并发编程的艺术》中关于线程状态的三处错误](https://mp.weixin.qq.com/s/UOrXql_LhOD8dhTq_EPI0w))
> 订正(来自[issue736](https://github.com/Snailclimb/JavaGuide/issues/736)):原图中 wait 到 runnable 状态的转换中,`join`实际上是`Thread`类的方法,但这里写成了`Object` ![Java 线程状态变迁图](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/java/concurrent/640.png)
由上图可以看出:线程创建之后它将处于 **NEW新建** 状态,调用 `start()` 方法后开始运行,线程这时候处于 **READY可运行** 状态。可运行状态的线程获得了 CPU 时间片timeslice后就处于 **RUNNING运行** 状态。 由上图可以看出:线程创建之后它将处于 **NEW新建** 状态,调用 `start()` 方法后开始运行,线程这时候处于 **READY可运行** 状态。可运行状态的线程获得了 CPU 时间片timeslice后就处于 **RUNNING运行** 状态。
> 在操作系统层面,线程有 READY 和 RUNNING 状态;而在 JVM 层面,只能看到 RUNNABLE 状态(图源:[HowToDoInJava](https://howtodoinJava.com/ "HowToDoInJava")[Java Thread Life Cycle and Thread States](https://howtodoinJava.com/Java/multi-threading/Java-thread-life-cycle-and-thread-states/ "Java Thread Life Cycle and Thread States")),所以 Java 系统一般将这两个状态统称为 **RUNNABLE运行中** 状态 。 > 在操作系统层面,线程有 READY 和 RUNNING 状态;而在 JVM 层面,只能看到 RUNNABLE 状态(图源:[HowToDoInJava](https://howtodoinJava.com/ "HowToDoInJava")[Java Thread Life Cycle and Thread States](https://howtodoinJava.com/Java/multi-threading/Java-thread-life-cycle-and-thread-states/ "Java Thread Life Cycle and Thread States")),所以 Java 系统一般将这两个状态统称为 **RUNNABLE运行中** 状态 。
> >
> **为什么 JVM 没有区分这两种状态呢?** (摘自:[java线程运行怎么有第六种状态 - Dawell的回答](https://www.zhihu.com/question/56494969/answer/154053599) 现在的<b>时分</b>time-sharing<b>多任务</b>multi-task操作系统架构通常都是用所谓的“<b>时间分片</b>time quantum or time slice”方式进行<b>抢占式</b>preemptive轮转调度round-robin式。这个时间分片通常是很小的一个线程一次最多只能在 CPU 上运行比如 10-20ms 的时间(此时处于 running 状态),也即大概只有 0.01 秒这一量级,时间片用后就要被切换下来放入调度队列的末尾等待再次调度。(也即回到 ready 状态)。线程切换的如此之快,区分这两种状态就没什么意义了。 > **为什么 JVM 没有区分这两种状态呢?** (摘自:[Java 线程运行怎么有第六种状态? - Dawell 的回答](https://www.zhihu.com/question/56494969/answer/154053599) 现在的时分time-sharing多任务multi-task操作系统架构通常都是用所谓的“时间分片time quantum or time slice”方式进行抢占式preemptive轮转调度round-robin 式)。这个时间分片通常是很小的,一个线程一次最多只能在 CPU 上运行比如 10-20ms 的时间(此时处于 running 状态),也即大概只有 0.01 秒这一量级,时间片用后就要被切换下来放入调度队列的末尾等待再次调度。(也即回到 ready 状态)。线程切换的如此之快,区分这两种状态就没什么意义了。
![RUNNABLE-VS-RUNNING](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-3/RUNNABLE-VS-RUNNING.png) ![RUNNABLE-VS-RUNNING](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-3/RUNNABLE-VS-RUNNING.png)
当线程执行 `wait()`方法之后,线程进入 **WAITING等待** 状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态,而 **TIMED_WAITING(超时等待)** 状态相当于在等待状态的基础上增加了超时限制,比如通过 `sleeplong millis`方法或 `waitlong millis`方法可以将 Java 线程置于 TIMED_WAITING 状态。当超时时间到达后 Java 线程将会返回到 RUNNABLE 状态。当线程调用同步方法时,在没有获取到锁的情况下,线程将会进入到 **BLOCKED阻塞** 状态。线程在执行 Runnable 的`run()`方法之后将会进入到 **TERMINATED终止** 状态。 - 当线程执行 `wait()`方法之后,线程进入 **WAITING等待** 状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态。
- **TIMED_WAITING(超时等待)** 状态相当于在等待状态的基础上增加了超时限制,比如通过 `sleeplong millis`方法或 `waitlong millis`方法可以将线程置于 TIMED_WAITING 状态。当超时时间结束后,线程将会返回到 RUNNABLE 状态。
- 当线程进入 `synchronized` 方法/块或者调用 `wait` 后(被 `notify`)重新进入 `synchronized` 方法/块,但是锁被其它线程占有,这个时候线程就会进入 **BLOCKED阻塞** 状态。
- 线程在执行完了 `run()`方法之后将会进入到 **TERMINATED终止** 状态。
相关阅读:[挑错 |《Java 并发编程的艺术》中关于线程状态的三处错误](https://mp.weixin.qq.com/s/UOrXql_LhOD8dhTq_EPI0w) 。 相关阅读:[线程的几种状态你真的了解么?](https://mp.weixin.qq.com/s/R5MrTsWvk9McFSQ7bS0W2w) 。
## 什么是上下文切换? ## 什么是上下文切换?
线程在执行过程中会有自己的运行条件和状态(也称上下文),比如上文所说到过的程序计数器,栈信息等。当出现如下情况的时候,线程会从占用 CPU 状态中退出。 线程在执行过程中会有自己的运行条件和状态(也称上下文),比如上文所说到过的程序计数器,栈信息等。当出现如下情况的时候,线程会从占用 CPU 状态中退出。
- 主动让出 CPU比如调用了 `sleep()`, `wait()` 等。 - 主动让出 CPU比如调用了 `sleep()`, `wait()` 等。
- 时间片用完因为操作系统要防止一个线程或者进程长时间占用CPU导致其他线程或者进程饿死。 - 时间片用完,因为操作系统要防止一个线程或者进程长时间占用 CPU 导致其他线程或者进程饿死。
- 调用了阻塞类型的系统中断,比如请求 IO线程被阻塞。 - 调用了阻塞类型的系统中断,比如请求 IO线程被阻塞。
- 被终止或结束运行 - 被终止或结束运行
@ -235,12 +251,12 @@ Thread[线程 2,5,main]waiting get resource1
避免死锁就是在资源分配时,借助于算法(比如银行家算法)对资源分配进行计算评估,使其进入安全状态。 避免死锁就是在资源分配时,借助于算法(比如银行家算法)对资源分配进行计算评估,使其进入安全状态。
> **安全状态** 指的是系统能够按照某种线程推进顺序P1、P2、P3.....Pn来为每个线程分配所需资源直到满足每个线程对资源的最大需求使每个线程都可顺利完成。称<P1P2P3.....Pn>序列为安全序列。 > **安全状态** 指的是系统能够按照某种线程推进顺序P1、P2、P3.....Pn来为每个线程分配所需资源直到满足每个线程对资源的最大需求使每个线程都可顺利完成。称 `<P1、P2、P3.....Pn>` 序列为安全序列。
我们对线程 2 的代码修改成下面这样就不会产生死锁了。 我们对线程 2 的代码修改成下面这样就不会产生死锁了。
```java ```java
new Thread(() -> { new Thread(() -> {
synchronized (resource1) { synchronized (resource1) {
System.out.println(Thread.currentThread() + "get resource1"); System.out.println(Thread.currentThread() + "get resource1");
try { try {
@ -256,7 +272,7 @@ Thread[线程 2,5,main]waiting get resource1
}, "线程 2").start(); }, "线程 2").start();
``` ```
Output 输出:
``` ```
Thread[线程 1,5,main]get resource1 Thread[线程 1,5,main]get resource1
@ -273,17 +289,29 @@ Process finished with exit code 0
线程 1 首先获得到 resource1 的监视器锁,这时候线程 2 就获取不到了。然后线程 1 再去获取 resource2 的监视器锁,可以获取到。然后线程 1 释放了对 resource1、resource2 的监视器锁的占用,线程 2 获取到就可以执行了。这样就破坏了破坏循环等待条件,因此避免了死锁。 线程 1 首先获得到 resource1 的监视器锁,这时候线程 2 就获取不到了。然后线程 1 再去获取 resource2 的监视器锁,可以获取到。然后线程 1 释放了对 resource1、resource2 的监视器锁的占用,线程 2 获取到就可以执行了。这样就破坏了破坏循环等待条件,因此避免了死锁。
## 说说 sleep() 方法和 wait() 方法区别和共同点? ## sleep() 方法和 wait() 方法对比
- 两者最主要的区别在于:**`sleep()` 方法没有释放锁,而 `wait()` 方法释放了锁** 。 **共同点** :两者都可以暂停线程的执行。
- 两者都可以暂停线程的执行。
- `wait()` 通常被用于线程间交互/通信,`sleep() `通常被用于暂停执行。
- `wait()` 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 `notify() `或者 `notifyAll()` 方法。`sleep() `方法执行完成后,线程会自动苏醒。或者可以使用 `wait(long timeout)` 超时后线程会自动苏醒。
## 为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法? **区别**
- **`sleep()` 方法没有释放锁,而 `wait()` 方法释放了锁** 。
- `wait()` 通常被用于线程间交互/通信,`sleep()`通常被用于暂停执行。
- `wait()` 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 `notify()`或者 `notifyAll()` 方法。`sleep()`方法执行完成后,线程会自动苏醒,或者也可以使用 `wait(long timeout)` 超时后线程会自动苏醒。
- `sleep()``Thread` 类的静态本地方法,`wait()` 则是 `Object` 类的本地方法。为什么这样设计呢?
## 为什么 wait() 方法不定义在 Thread 中?
`wait()` 是让获得对象锁的线程实现等待,会自动释放当前线程占有的对象锁。每个对象(`Object`)都拥有对象锁,既然要释放当前线程占有的对象锁并让其进入 WAITING 状态,自然是要操作对应的对象(`Object`)而非当前的线程(`Thread`)。
类似的问题:**为什么 `sleep()` 方法定义在 `Thread` 中?**
因为 `sleep()` 是让当前线程暂停执行,不涉及到对象类,也不需要获得对象锁。
## 可以直接调用 Thread 类的 run 方法吗?
这是另一个非常经典的 Java 多线程面试问题,而且在面试中会经常被问到。很简单,但是很多人都会答不上来! 这是另一个非常经典的 Java 多线程面试问题,而且在面试中会经常被问到。很简单,但是很多人都会答不上来!
new 一个 Thread线程进入了新建状态。调用 `start()`方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。 `start()` 会执行线程的相应准备工作,然后自动执行 `run()` 方法的内容,这是真正的多线程工作。 但是,直接执行 `run()` 方法,会把 `run()` 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。 new 一个 `Thread`,线程进入了新建状态。调用 `start()`方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。 `start()` 会执行线程的相应准备工作,然后自动执行 `run()` 方法的内容,这是真正的多线程工作。 但是,直接执行 `run()` 方法,会把 `run()` 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。
**总结: 调用 `start()` 方法方可启动线程并使线程进入就绪状态,直接执行 `run()` 方法的话不会以多线程的方式执行。** **总结: 调用 `start()` 方法方可启动线程并使线程进入就绪状态,直接执行 `run()` 方法的话不会以多线程的方式执行。**

View File

@ -22,7 +22,9 @@ JMMJava 内存模型)相关的问题比较多,也比较重要,于是我
在 Java 中,`volatile` 关键字可以保证变量的可见性,如果我们将变量声明为 **`volatile`** ,这就指示 JVM这个变量是共享且不稳定的每次使用它都到主存中进行读取。 在 Java 中,`volatile` 关键字可以保证变量的可见性,如果我们将变量声明为 **`volatile`** ,这就指示 JVM这个变量是共享且不稳定的每次使用它都到主存中进行读取。
![JMM(Java 内存模型)](./images/jmm/jmm.png) ![JMM(Java 内存模型)](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/java/concurrent/jmm.png)
![JMM(Java 内存模型)强制在主存中进行读取](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/java/concurrent/jmm2.png)
`volatile` 关键字其实并非是 Java 语言特有的,在 C 语言里也有,它最原始的意义就是禁用 CPU 缓存。如果我们将一个变量使用 `volatile` 修饰,这就指示 编译器,这个变量是共享且不稳定的,每次使用它都到主存中进行读取。 `volatile` 关键字其实并非是 Java 语言特有的,在 C 语言里也有,它最原始的意义就是禁用 CPU 缓存。如果我们将一个变量使用 `volatile` 修饰,这就指示 编译器,这个变量是共享且不稳定的,每次使用它都到主存中进行读取。

View File

@ -88,7 +88,7 @@ JMM 说白了就是定义了一些规范来解决这些问题,开发发者可
Java 内存模型的抽象示意图如下: Java 内存模型的抽象示意图如下:
![JMM(Java 内存模型)](./images/jmm/jmm.png) ![JMM(Java 内存模型)](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/java/concurrent/jmm.png)
从上图来看,线程 1 与线程 2 之间如果要进行通信的话,必须要经历下面 2 个步骤: 从上图来看,线程 1 与线程 2 之间如果要进行通信的话,必须要经历下面 2 个步骤:

View File

@ -25,11 +25,11 @@ Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成
**JDK 1.8 之前** **JDK 1.8 之前**
![](./pictures/java内存区域/JVM运行时数据区域.png) ![Java 运行时数据区域JDK1.8 之前)](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/java/jvm/java-runtime-data-areas-jdk1.7.png)
**JDK 1.8** **JDK 1.8 之后**
![](./pictures/java内存区域/Java运行时数据区域JDK1.8.png) ![Java 运行时数据区域JDK1.8 之后)](https://guide-blog-images.oss-cn-shenzhen.aliyuncs.com/github/javaguide/java/jvm/java-runtime-data-areas-jdk1.8.png)
**线程私有的:** **线程私有的:**

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

View File

@ -0,0 +1 @@
<mxfile host="Electron" modified="2022-08-12T06:20:50.190Z" agent="5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.4.5 Chrome/83.0.4103.122 Electron/9.1.0 Safari/537.36" etag="0aZpmGB0zKjtoZiNRr2d" version="13.4.5" type="device"><diagram id="cOLtUwHyX4POJW0G9AIN" name="Page-1">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</diagram></mxfile>

View File

@ -0,0 +1 @@
<mxfile host="Electron" modified="2022-08-12T06:12:35.835Z" agent="5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/13.4.5 Chrome/83.0.4103.122 Electron/9.1.0 Safari/537.36" etag="BQ3VE-MOU7lptXVcE5UA" version="13.4.5" type="device"><diagram id="cOLtUwHyX4POJW0G9AIN" name="Page-1">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</diagram></mxfile>