diff --git a/README.md b/README.md index a52a172..7a73df4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ 本仓库是对 Java 的一些基础知识、数据库知识、以及框架知识进行收集、整理(持续更新中)。
-仓库对应 WebSite:https://duhouan.github.io/Java/#/ +仓库对应 WebSite:https://duhouan.github.io/Java/#
+如何流畅访问 Github -
+
diff --git "a/docs/AimForOffer/\346\225\260\346\215\256\347\273\223\346\236\204\347\233\270\345\205\263/2_\345\255\227\347\254\246\344\270\262.md" "b/docs/AimForOffer/\346\225\260\346\215\256\347\273\223\346\236\204\347\233\270\345\205\263/2_\345\255\227\347\254\246\344\270\262.md" index b944880..619b66a 100644 --- "a/docs/AimForOffer/\346\225\260\346\215\256\347\273\223\346\236\204\347\233\270\345\205\263/2_\345\255\227\347\254\246\344\270\262.md" +++ "b/docs/AimForOffer/\346\225\260\346\215\256\347\273\223\346\236\204\347\233\270\345\205\263/2_\345\255\227\347\254\246\344\270\262.md" @@ -393,7 +393,7 @@ private void reverse(char[] chs,int start,int end){ 最朴素的方法就是依次从待匹配串的每一个位置开始,逐一与模版串匹配, 因为最多检查 (n - m)个位置,所以方法的复杂度为 O(m*(n-1))。 -
+
```java //haystack 是待匹配串 diff --git "a/docs/AimForOffer/\347\256\227\346\263\225\346\200\235\346\203\263\347\233\270\345\205\263/4_\346\220\234\347\264\242.md" "b/docs/AimForOffer/\347\256\227\346\263\225\346\200\235\346\203\263\347\233\270\345\205\263/4_\346\220\234\347\264\242.md" index 71fc0df..3bbfe62 100644 --- "a/docs/AimForOffer/\347\256\227\346\263\225\346\200\235\346\203\263\347\233\270\345\205\263/4_\346\220\234\347\264\242.md" +++ "b/docs/AimForOffer/\347\256\227\346\263\225\346\200\235\346\203\263\347\233\270\345\205\263/4_\346\220\234\347\264\242.md" @@ -230,15 +230,15 @@ public boolean exist(char[][] board, String word) { [N皇后](https://leetcode-cn.com/problems/n-queens/) -
+
-
+
- 思路: -
+
-
+
在第 i 行放上皇后,判断是否其他地方能够放皇后的情况: @@ -250,7 +250,7 @@ dia1[1] =true 就表示 [0,1]和[1,0] 位置不能放皇后。 对角线1总共有 (2*n-1) 条;m 与 i 、 j 的关系:m=i+j。 -
+
(3)对角线2:dai2[m]表示第 m 条对角线被2占用,如 dai2[0]=true 表示[0,3] 位置不能放皇后, @@ -258,7 +258,7 @@ dai2[2]=true 则表示 [0,2] 和 [1,3] 不能放皇后, 对角线2总共有(2*n-1)条;m 与 i、j 关系:m=i-j+n-1。 -
+
```java private List> res; diff --git "a/docs/AimForOffer/\347\256\227\346\263\225\346\200\235\346\203\263\347\233\270\345\205\263/5_\346\216\222\345\210\227\347\273\204\345\220\210.md" "b/docs/AimForOffer/\347\256\227\346\263\225\346\200\235\346\203\263\347\233\270\345\205\263/5_\346\216\222\345\210\227\347\273\204\345\220\210.md" index f33b398..f5fac2e 100644 --- "a/docs/AimForOffer/\347\256\227\346\263\225\346\200\235\346\203\263\347\233\270\345\205\263/5_\346\216\222\345\210\227\347\273\204\345\220\210.md" +++ "b/docs/AimForOffer/\347\256\227\346\263\225\346\200\235\346\203\263\347\233\270\345\205\263/5_\346\216\222\345\210\227\347\273\204\345\220\210.md" @@ -4,7 +4,7 @@ [全排列](https://leetcode-cn.com/problems/permutations/) -
+
```java private List> res; diff --git "a/docs/DataBase/1_\346\225\260\346\215\256\345\272\223\347\263\273\347\273\237\345\216\237\347\220\206.md" "b/docs/DataBase/1_\346\225\260\346\215\256\345\272\223\347\263\273\347\273\237\345\216\237\347\220\206.md" index d34f747..885bf91 100644 --- "a/docs/DataBase/1_\346\225\260\346\215\256\345\272\223\347\263\273\347\273\237\345\216\237\347\220\206.md" +++ "b/docs/DataBase/1_\346\225\260\346\215\256\345\272\223\347\263\273\347\273\237\345\216\237\347\220\206.md" @@ -38,25 +38,25 @@ T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。 -
+
### 脏读 T1 修改一个数据,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。 -
+
### 不可重复读 T2 读取一个数据,T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同。 -
+
### 幻影读 T1 读取某个**范围**的数据,T2 在这个**范围**内插入新的数据,T1 再次读取这个**范围**的数据,此时读取的结果和和第一次读取的结果不同。 -
+
## 事务隔离级别 diff --git "a/docs/DataBase/2_\345\205\263\347\263\273\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241\347\220\206\350\256\272.md" "b/docs/DataBase/2_\345\205\263\347\263\273\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241\347\220\206\350\256\272.md" index 3846303..244398b 100644 --- "a/docs/DataBase/2_\345\205\263\347\263\273\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241\347\220\206\350\256\272.md" +++ "b/docs/DataBase/2_\345\205\263\347\263\273\346\225\260\346\215\256\345\272\223\350\256\276\350\256\241\347\220\206\350\256\272.md" @@ -34,7 +34,7 @@ 高级别范式的依赖于低级别的范式,1NF 是最低级别的范式。 -
+
diff --git "a/docs/DataBase/3_\350\256\276\350\256\241\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223.md" "b/docs/DataBase/3_\350\256\276\350\256\241\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223.md" index c76e11e..0309567 100644 --- "a/docs/DataBase/3_\350\256\276\350\256\241\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223.md" +++ "b/docs/DataBase/3_\350\256\276\350\256\241\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223.md" @@ -2,7 +2,7 @@ 关系数据库管理系统(RDBMS)架构图如下: -
+
## 存储 diff --git "a/docs/DataBase/5_LeetCode_Database\351\242\230\350\247\243.md" "b/docs/DataBase/5_LeetCode_Database\351\242\230\350\247\243.md" index c3d52b5..0f3123f 100644 --- "a/docs/DataBase/5_LeetCode_Database\351\242\230\350\247\243.md" +++ "b/docs/DataBase/5_LeetCode_Database\351\242\230\350\247\243.md" @@ -422,15 +422,15 @@ ON p.PersonId=a.PersonId; * 内连接:返回两张表的交集部分。 -
+
* 左连接: -
+
* 右连接: -
+
# *8、超过经理收入的员工(181) diff --git "a/docs/JVM/1_Java\345\206\205\345\255\230\345\214\272\345\237\237.md" "b/docs/JVM/1_Java\345\206\205\345\255\230\345\214\272\345\237\237.md" index ac756ed..ae76568 100644 --- "a/docs/JVM/1_Java\345\206\205\345\255\230\345\214\272\345\237\237.md" +++ "b/docs/JVM/1_Java\345\206\205\345\255\230\345\214\272\345\237\237.md" @@ -8,7 +8,7 @@ JDK 1.8 和之前的版本略有不同: - JDK 1.7 字符串常量池被从方法区中拿到了堆,运行时常量池剩下的内容还在方法区 - JDK1.8 HotSpot 虚拟机**移除了永久代**,采用**元空间(Metaspace)** 代替方法区,这时候**字符串常量池还在堆**,运行时常量池还在方法区,只不过方法区的实现从永久代变成了元空间。 -
+
## 程序计数器 @@ -28,7 +28,7 @@ JDK 1.8 和之前的版本略有不同: 每个 Java 方法在执行的同时会创建一个栈帧用于存储**局部变量表**、**操作数栈**、动态链接、方法出口信息等。 -
+
从方法调用直至执行完成的过程,就对应着**一个栈帧在 Java 虚拟机栈中入栈和出栈的过程**。Java 方法有两种返回方式: @@ -121,7 +121,7 @@ javap -verbose JVMTest - 执行 iload_2,将 2 位置元素(数值 3)push 进操作数栈 - 执行 ireturn,返回操作数栈栈顶元素 -
+
## 本地方法栈 @@ -157,11 +157,11 @@ JDK 7 版本及 JDK 7 版本之前,Hotspot 虚拟机的堆结构如下: - 老年代 (Old Generation) - 永久代 (Permanent Generation) -
+
JDK 8 版本之后 HotSpot 虚拟机的永久代被彻底移除了,取而代之是元空间,元空间使用的是直接内存。 -
+
## 堆和栈的关系 @@ -333,7 +333,7 @@ str1、str2 是从字符串常量池中获取的对象。 对于 str5,字符串常量池已有 "helloworld" 对象,str5 直接引用该对象。 -
+
所以,尽量避免多个字符串拼接,因为这样会重新创建新的对象。如果需要改变字符串的话,可以使用 StringBuilder 或者 StringBuffer。 @@ -353,7 +353,7 @@ str1、str2 是从字符串常量池中获取的对象。 - 实例数据 - 对齐填充 -
+
### 对象头 @@ -444,13 +444,13 @@ Java 对象的创建过程分为以下5步: 如果使用句柄的话,那么 Java 堆中将会划分出一块内存来作为句柄池,reference 中存储的就是**对象的句柄地址**,而句柄中包含了对象实例数据与类型数据各自的具体地址信息 。 -
+
### 直接指针 如果使用直接指针访问,那么 Java 堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而 reference 中存储的直接就是**对象的地址**。 -
+
这两种对象访问方式各有优势: diff --git "a/docs/JVM/2_\345\236\203\345\234\276\346\224\266\351\233\206.md" "b/docs/JVM/2_\345\236\203\345\234\276\346\224\266\351\233\206.md" index da881ac..020c177 100644 --- "a/docs/JVM/2_\345\236\203\345\234\276\346\224\266\351\233\206.md" +++ "b/docs/JVM/2_\345\236\203\345\234\276\346\224\266\351\233\206.md" @@ -40,7 +40,7 @@ public class Test { 以 GC Roots 为起始点进行搜索,可达的对象都是存活的,不可达的对象可被回收。 -
+
**Java 虚拟机使用可达性分析算法来判断对象是否可被回收**,GC Roots 一般包含以下几种: @@ -165,7 +165,7 @@ obj = null; ### “标记-清除” 算法 -
+
在标记阶段,从根集合进行扫描,会检查每个对象是否为活动对象,如果是活动对象,则程序会在对象头部打上标记。 @@ -180,7 +180,7 @@ obj = null; ### ”标记-整理“ 算法 -
+
标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。 @@ -190,7 +190,7 @@ obj = null; ### ”复制“ 算法 -
+
将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。 @@ -275,7 +275,7 @@ SafePoint 的选择很重要,如果太少可能导致 GC 等待的时间太长 **现在标准:在最大吞吐量优先的情况下,降低停顿时间**。 -
+
@@ -285,7 +285,7 @@ SafePoint 的选择很重要,如果太少可能导致 GC 等待的时间太长 虽然我们对各个收集器进行比较,但并非要挑选出一个最好的收集器。因为直到现在为止还没有最好的垃圾收集器出现,更加没有万能的垃圾收集器,我们能做的就是**根据具体应用场景选择适合自己的垃圾收集器**。 -
+
以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。 JDK 9 取消了对 Serial+CMS、 ParNew+Serial Old 这两个组合的支持。 @@ -295,7 +295,7 @@ ParNew+Serial Old 这两个组合的支持。 #### 1. Serial 收集器 -
+
Serial 翻译为串行,也就是说它以串行的方式执行。 @@ -307,7 +307,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。 #### 2. ParNew 收集器 -
+
它是 Serial 收集器的多线程版本。 @@ -327,7 +327,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。 #### 4. Serial Old 收集器 -
+
是 Serial 收集器的老年代版本,也是给 Client 场景下的虚拟机使用。如果用在 Server 场景下,它有两大用途: @@ -336,7 +336,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。 #### 5. Parallel Old 收集器 -
+
是 Parallel Scavenge 收集器的老年代版本。 @@ -344,7 +344,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。 #### 6. CMS 收集器 -
+
CMS(Concurrent Mark Sweep),Mark Sweep 指的是标记 - 清除算法。 @@ -371,7 +371,7 @@ G1(Garbage-First),它是一款面向服务端应用的垃圾收集器, 堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。 -
+
G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离。 @@ -379,7 +379,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和 每个 Region 都有一个 Remembered Set,用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set,在做可达性分析的时候就可以避免全堆扫描。 -
+
如果不计算维护 Remembered Set 的操作,G1 收集器的运作大致可划分为以下几个步骤: diff --git "a/docs/JVM/5_\347\261\273\346\226\207\344\273\266\347\273\223\346\236\204.md" "b/docs/JVM/5_\347\261\273\346\226\207\344\273\266\347\273\223\346\236\204.md" index a9fc6ad..33dbf92 100644 --- "a/docs/JVM/5_\347\261\273\346\226\207\344\273\266\347\273\223\346\236\204.md" +++ "b/docs/JVM/5_\347\261\273\346\226\207\344\273\266\347\273\223\346\236\204.md" @@ -36,7 +36,7 @@ ClassFile { 通过分析 ClassFilee,得到 class 文件的组成:
- +
diff --git "a/docs/JVM/6_\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" "b/docs/JVM/6_\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" index 2cdf450..210636c 100644 --- "a/docs/JVM/6_\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" +++ "b/docs/JVM/6_\347\261\273\345\212\240\350\275\275\346\234\272\345\210\266.md" @@ -282,7 +282,7 @@ JDK 自带的 BootstrapClassLoader, ExtClassLoader 和 AppClassLoader 负责加 每一个类都有一个对应它的类加载器。系统中的 ClassLoader 在协同工作的时候会默认使用双亲委派模型(Parents Delegation Model)。该模型要求除了顶层的启动类加载器外,其它的类加载器都要有自己的父类加载器。这里的父子关系一般通过组合关系(Composition)来实现,而不是继承关系(Inheritance)。 -
+
### 1. 工作过程 diff --git "a/docs/JVM/7_Java\347\250\213\345\272\217\347\274\226\350\257\221\345\222\214\350\277\220\350\241\214\350\277\207\347\250\213.md" "b/docs/JVM/7_Java\347\250\213\345\272\217\347\274\226\350\257\221\345\222\214\350\277\220\350\241\214\350\277\207\347\250\213.md" index a1ca5db..6e207c6 100644 --- "a/docs/JVM/7_Java\347\250\213\345\272\217\347\274\226\350\257\221\345\222\214\350\277\220\350\241\214\350\277\207\347\250\213.md" +++ "b/docs/JVM/7_Java\347\250\213\345\272\217\347\274\226\350\257\221\345\222\214\350\277\220\350\241\214\350\277\207\347\250\213.md" @@ -75,7 +75,7 @@ JVM 以一个直接指向方法区 Person 类的指针替换了常量池中第 执行 p.sayHello(),JVM 根据栈中 p 的引用找到 Person 对象,然后根据 Person 对象持有的引用定位到方法区中 Person 类类信息的**方法表**,获得 sayHello 方法的字节码地址,然后开始运行方法。
- +
diff --git "a/docs/JavaBasics/6_\345\217\215\345\260\204.md" "b/docs/JavaBasics/6_\345\217\215\345\260\204.md" index 19ee986..ba3e78a 100644 --- "a/docs/JavaBasics/6_\345\217\215\345\260\204.md" +++ "b/docs/JavaBasics/6_\345\217\215\345\260\204.md" @@ -6,7 +6,7 @@ Java 异常是一个描述在代码段中**发生异常的对象**,当发生 ## 异常继承体系 -
+
Throwable 可以用来表示任何可以作为异常抛出的类,分为两种: **Error** 和 **Exception**。 @@ -18,7 +18,7 @@ Java 异常分为两种: - 受检异常:**除了 RuntimeException 及其子类以外,其他的 Exception 类及其子类都属于这种异常**。 - 非受检异常:包括 RuntimeException 及其子类和 Error。 -
+
注意:非受检查异常为编译器不要求强制处理的异常,受检异常则是编译器要求必须处置的异常。 @@ -109,7 +109,7 @@ Java规定:一个方法必须捕捉,或者声明抛出方法之外。 ## try-catch-finally语句块的执行 -

+

(1) try 块:用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块。 diff --git "a/docs/JavaContainer/1_\345\256\271\345\231\250\346\246\202\350\247\210.md" "b/docs/JavaContainer/1_\345\256\271\345\231\250\346\246\202\350\247\210.md" index 9ea4bab..26515fb 100644 --- "a/docs/JavaContainer/1_\345\256\271\345\231\250\346\246\202\350\247\210.md" +++ "b/docs/JavaContainer/1_\345\256\271\345\231\250\346\246\202\350\247\210.md" @@ -6,7 +6,7 @@ Collection 集合体系图: -
+
### 1. Set @@ -37,7 +37,7 @@ Collection 集合体系图: Map 集合体系图: -
+
- TreeMap:基于红黑树实现。 diff --git "a/docs/JavaContainer/2_\345\256\271\345\231\250\344\270\255\347\232\204\350\256\276\350\256\241\346\250\241\345\274\217.md" "b/docs/JavaContainer/2_\345\256\271\345\231\250\344\270\255\347\232\204\350\256\276\350\256\241\346\250\241\345\274\217.md" index dd0797c..f795cad 100644 --- "a/docs/JavaContainer/2_\345\256\271\345\231\250\344\270\255\347\232\204\350\256\276\350\256\241\346\250\241\345\274\217.md" +++ "b/docs/JavaContainer/2_\345\256\271\345\231\250\344\270\255\347\232\204\350\256\276\350\256\241\346\250\241\345\274\217.md" @@ -2,7 +2,7 @@ ## 迭代器模式 -

+

Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。 diff --git "a/docs/JavaContainer/3_\345\256\271\345\231\250\346\272\220\347\240\201\345\210\206\346\236\220 - List.md" "b/docs/JavaContainer/3_\345\256\271\345\231\250\346\272\220\347\240\201\345\210\206\346\236\220 - List.md" index 807c4aa..161d764 100644 --- "a/docs/JavaContainer/3_\345\256\271\345\231\250\346\272\220\347\240\201\345\210\206\346\236\220 - List.md" +++ "b/docs/JavaContainer/3_\345\256\271\345\231\250\346\272\220\347\240\201\345\210\206\346\236\220 - List.md" @@ -248,7 +248,7 @@ transient Node first; transient Node last; ``` -
+
### 2. 添加元素 将元素添加到链表尾部: diff --git "a/docs/JavaContainer/4_\345\256\271\345\231\250\346\272\220\347\240\201\345\210\206\346\236\220 - Map.md" "b/docs/JavaContainer/4_\345\256\271\345\231\250\346\272\220\347\240\201\345\210\206\346\236\220 - Map.md" index 33ae11e..595262c 100644 --- "a/docs/JavaContainer/4_\345\256\271\345\231\250\346\272\220\347\240\201\345\210\206\346\236\220 - Map.md" +++ "b/docs/JavaContainer/4_\345\256\271\345\231\250\346\272\220\347\240\201\345\210\206\346\236\220 - Map.md" @@ -18,7 +18,7 @@ Entry 存储着键值对。它包含了四个字段,从 next 字段我们可 即数组中的每个位置被当成一个桶,一个桶存放一个链表。HashMap 使用**拉链法**来解决冲突, 同一个链表中存放哈希值相同的 Entry。 -

+

```java static class Entry implements Map.Entry { @@ -98,7 +98,7 @@ map.put("K3", "V3"); - 计算键值对所在的桶; - 在链表上顺序查找,时间复杂度显然和链表的长度成正比。 -

+

### 3. put 操作 diff --git "a/docs/JavaContainer/5_\345\256\271\345\231\250\346\272\220\347\240\201\345\210\206\346\236\220 - \345\271\266\345\217\221\345\256\271\345\231\250.md" "b/docs/JavaContainer/5_\345\256\271\345\231\250\346\272\220\347\240\201\345\210\206\346\236\220 - \345\271\266\345\217\221\345\256\271\345\231\250.md" index 95408bf..98396c2 100644 --- "a/docs/JavaContainer/5_\345\256\271\345\231\250\346\272\220\347\240\201\345\210\206\346\236\220 - \345\271\266\345\217\221\345\256\271\345\231\250.md" +++ "b/docs/JavaContainer/5_\345\256\271\345\231\250\346\272\220\347\240\201\345\210\206\346\236\220 - \345\271\266\345\217\221\345\256\271\345\231\250.md" @@ -103,7 +103,7 @@ final Segment[] segments; static final int DEFAULT_CONCURRENCY_LEVEL = 16; ``` -
+
### 2. size 操作 diff --git "a/docs/JavaIO/3_\345\255\227\350\212\202\346\223\215\344\275\234.md" "b/docs/JavaIO/3_\345\255\227\350\212\202\346\223\215\344\275\234.md" index 9ca0b8b..c0c9cc6 100644 --- "a/docs/JavaIO/3_\345\255\227\350\212\202\346\223\215\344\275\234.md" +++ "b/docs/JavaIO/3_\345\255\227\350\212\202\346\223\215\344\275\234.md" @@ -309,7 +309,7 @@ Java I/O 使用了装饰者模式来实现。以 InputStream 为例, - FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作; - FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能。例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。 -

+

实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。 diff --git "a/docs/JavaIO/6_\347\275\221\347\273\234\346\223\215\344\275\234.md" "b/docs/JavaIO/6_\347\275\221\347\273\234\346\223\215\344\275\234.md" index e9edb40..eaa5928 100644 --- "a/docs/JavaIO/6_\347\275\221\347\273\234\346\223\215\344\275\234.md" +++ "b/docs/JavaIO/6_\347\275\221\347\273\234\346\223\215\344\275\234.md" @@ -67,7 +67,7 @@ public static void main(String[] args) throws IOException { - Socket:客户端类 - 服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。 -
+
## Datagram diff --git a/docs/JavaIO/7_NIO.md b/docs/JavaIO/7_NIO.md index a265619..537fe3a 100644 --- a/docs/JavaIO/7_NIO.md +++ b/docs/JavaIO/7_NIO.md @@ -65,23 +65,23 @@ I/O 包和 NIO 已经很好地集成了,java.io.\* 已经以 NIO 为基础重 ① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0,而 limit = capacity = 8。capacity 变量不会改变,下面的讨论会忽略它。 -

+

② 从输入通道中读取 5 个字节数据写入缓冲区中,此时 position 为 5,limit 保持不变。 -

+

③ 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position,并将 position 设置为 0。 -

+

④ 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。 -

+

⑤ 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。 -

+

## 文件 NIO 实例 ### FileChannel的使用 @@ -427,7 +427,7 @@ NIO 实现了 IO 多路复用中的 **Reactor 模型**,一个线程 Thread 使 应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能, 为 FileChannel 配置非阻塞也没有意义。 -

+

使用Selector的优点: diff --git "a/docs/Java_Concurrency/1_\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/docs/Java_Concurrency/1_\345\237\272\347\241\200\347\237\245\350\257\206.md" index 4b612ec..4850e65 100644 --- "a/docs/Java_Concurrency/1_\345\237\272\347\241\200\347\237\245\350\257\206.md" +++ "b/docs/Java_Concurrency/1_\345\237\272\347\241\200\347\237\245\350\257\206.md" @@ -77,7 +77,7 @@ Java 程序是多线程程序,这是因为 JVM 启动至少了主线程和垃 单就一个 CPU 而言两个线程可以解决线程阻塞造成的不流畅问题,其本身运行效率并没有提高, 多 CPU 的并行运算才真正解决了运行效率问题,这也正是并发和并行的区别。 -
+
@@ -513,7 +513,7 @@ yield() 和 wait() 的区别: 线程在生命周期中并不是固定处于某一个状态而是随着代码的执行在不同状态之间切换: -
+
diff --git "a/docs/Java_Concurrency/2_\345\271\266\345\217\221\347\220\206\350\256\272.md" "b/docs/Java_Concurrency/2_\345\271\266\345\217\221\347\220\206\350\256\272.md" index dca44b1..e354e7a 100644 --- "a/docs/Java_Concurrency/2_\345\271\266\345\217\221\347\220\206\350\256\272.md" +++ "b/docs/Java_Concurrency/2_\345\271\266\345\217\221\347\220\206\350\256\272.md" @@ -14,7 +14,7 @@ Java 内存模型(即 Java Memory Model,简称 JMM)试图屏蔽各种硬 当 CPU 需要将结果写回到主存中去时,它会将内部寄存器的值刷新到缓存中,然后在某个时间点将值刷新回主存。 -
+
加入 CPU 缓存带来了一些新的问题: @@ -27,13 +27,13 @@ JMM 规定线程之间的共享变量存放在主内存(主内存就是硬件 **线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成**。 -
+
### 主内存和工作内存的交互 JMM 定义了 8 个操作来完成主内存和工作内存的交互操作。 -
+
- lock(锁定):作用于主内存的变量,把一个变量标识为一条线程独占状态。 - unlock(解锁):作用于主内存变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。 diff --git "a/docs/Java_Concurrency/3_\345\271\266\345\217\221\345\205\263\351\224\256\345\255\227.md" "b/docs/Java_Concurrency/3_\345\271\266\345\217\221\345\205\263\351\224\256\345\255\227.md" index b2535bd..b5f5193 100644 --- "a/docs/Java_Concurrency/3_\345\271\266\345\217\221\345\205\263\351\224\256\345\255\227.md" +++ "b/docs/Java_Concurrency/3_\345\271\266\345\217\221\345\205\263\351\224\256\345\255\227.md" @@ -139,7 +139,7 @@ public class SynchronizedDemo { } ``` -
+
任意一个对象都拥有自己的 Monitor,当这个对象由同步块或者同步方法调用时, 执行方法的线程必须先获取该对象的 Monitor 才能进入同步块和同步方法, 如果没有获取到 Monitor 的线程将会被阻塞在同步块和同步方法的入口处,进入到 BLOCKED 状态。 diff --git "a/docs/Java_Concurrency/6_\345\271\266\345\217\221\345\256\271\345\231\250.md" "b/docs/Java_Concurrency/6_\345\271\266\345\217\221\345\256\271\345\231\250.md" index 8372a11..910c97a 100644 --- "a/docs/Java_Concurrency/6_\345\271\266\345\217\221\345\256\271\345\231\250.md" +++ "b/docs/Java_Concurrency/6_\345\271\266\345\217\221\345\256\271\345\231\250.md" @@ -113,7 +113,7 @@ final Segment[] segments; static final int DEFAULT_CONCURRENCY_LEVEL = 16; ``` -
+
### 2. size 操作 diff --git "a/docs/Java_Concurrency/7_\345\271\266\345\217\221\345\267\245\345\205\267.md" "b/docs/Java_Concurrency/7_\345\271\266\345\217\221\345\267\245\345\205\267.md" index 9ff22a0..35812b7 100644 --- "a/docs/Java_Concurrency/7_\345\271\266\345\217\221\345\267\245\345\205\267.md" +++ "b/docs/Java_Concurrency/7_\345\271\266\345\217\221\345\267\245\345\205\267.md" @@ -113,7 +113,7 @@ final Segment[] segments; static final int DEFAULT_CONCURRENCY_LEVEL = 16; ``` -
+
### 2. size 操作 @@ -258,7 +258,7 @@ java.util.concurrent(J.U.C)大大提高了并发性能,AQS 被认为是 J. 维护了一个计数器 cnt,每次调用 countDown() 方法会让计数器的值减 1,减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。 -
+
```java public class CountdownLatchExample { @@ -307,7 +307,7 @@ public CyclicBarrier(int parties) { } ``` -
+
```java public class CyclicBarrierExample { diff --git "a/docs/Java_Concurrency/8_\347\272\277\347\250\213\346\261\240.md" "b/docs/Java_Concurrency/8_\347\272\277\347\250\213\346\261\240.md" index ecdbd56..3dc260d 100644 --- "a/docs/Java_Concurrency/8_\347\272\277\347\250\213\346\261\240.md" +++ "b/docs/Java_Concurrency/8_\347\272\277\347\250\213\346\261\240.md" @@ -6,7 +6,7 @@ Executor 框架是在 Java5 中引入的,**通过该框架来控制线程的 Executor 基于**生产者-消费者模式**,**提交任务的线程相当于生产者,执行任务的线程相当于消费者**。同时,Executor 的实现还提供了对任务执行的生命周期管理的支持。 -
+
- Executor @@ -48,7 +48,7 @@ Eexcutor 框架由 3 大部分组成: 异步任务需要返回结果,提交任务后需要返回 Future, FutureTask 实现。 -
+
运行过程: @@ -190,7 +190,7 @@ private static ExecutorService executor = 状态转换图: -![img](https://gitee.com/duhouan/ImagePro/raw/master/pics/concurrent/c_22.png) +![img](https://github.com/DuHouAn/ImagePro/raw/master/pics/concurrent/c_22.png) shutdown() 和 shutdownNow() 这两个方法的原理都是**遍历线程池中所有的线程,然后依次中断线程**。 shutdown() 和 shutdownNow() 还是有不一样的地方: diff --git "a/docs/Java_Concurrency/9_\345\271\266\345\217\221\345\256\236\350\267\265.md" "b/docs/Java_Concurrency/9_\345\271\266\345\217\221\345\256\236\350\267\265.md" index 24738af..3707d11 100644 --- "a/docs/Java_Concurrency/9_\345\271\266\345\217\221\345\256\236\350\267\265.md" +++ "b/docs/Java_Concurrency/9_\345\271\266\345\217\221\345\256\236\350\267\265.md" @@ -6,7 +6,7 @@ 假设线程 A 持有资源 1,线程 B 持有资源 2,它们同时都想申请对方的资源,那么这两个线程就会互相等待而进入死锁状态。 -
+
使用 Java 代码模拟上述死锁场景: @@ -533,7 +533,7 @@ public class ThreadLocalExample1 { 其对应的底层结构图为: -
+
由上图可以看出,ThreadLocal 从理论上讲并不是用来解决多线程并发问题的,因为根本不存在多线程竞争。 diff --git a/docs/Kafka&RabbitMQ/Kafka.md b/docs/Kafka&RabbitMQ/Kafka.md index 0374b45..9d38cbb 100644 --- a/docs/Kafka&RabbitMQ/Kafka.md +++ b/docs/Kafka&RabbitMQ/Kafka.md @@ -26,7 +26,7 @@ Partition 即分区,每个 Topic 包含一个或多个分区。 消息发送时都被发送到一个 Topic 中,其本质就是一个目录,而 Topic 由是由一些 Partition Logs(分区日志)组成,其组织结构如下: -
+
**每个 Partition 中的消息都是有序的**,生产的消息被不断追加到 Partition Log 上,其中的每一个消息都被赋予了一个唯一的 offset 值,Kafka 通过 **offset 保证消息在分区内的顺序**,offset 的顺序性不跨分区,即 Kafka 只保证在同一个分区内的消息是有序的;同一 Topic 的多个分区内的消息,Kafka 并不保证其顺序性。 @@ -52,7 +52,7 @@ Kafka 中每个 Partition 可以有多个副本(Replication),每个副本 一般情况下,同一分区的多个副本会被分配到不同的 Broker上。当 Leader 所在的 Broker 宕机之后,可以重新选举新的 Leader,继续对外提供服务。 -
+
## Producer @@ -98,7 +98,7 @@ Kafka 提供了两套 Consumer Api,分为 Simple Api 和 High-Level Api。 High-Level API 还支持以组的形式消费 Topic,如果 Consumers 有同一个组名,那么 Kafka 就相当于一个队列消息服务,而各个 Consumer 均衡地消费相应 Partition 中的数据。若 Consumers 有不同的组名,那么此时 Kafka 就相当于一个广播服务,会把 Topic 中的所有消息广播到每个 Consumer。 -
+
## Consumer Group @@ -108,7 +108,7 @@ Consumer Group 即消费者组,多个 Consumer 可以组成一个 Consumer Gro Producer、Consumer 和 Consumer Group 之间的关系如下图: -
+
@@ -132,7 +132,7 @@ Zookeeper 为 Kafka 提供集群的管理。不仅保存着集群的 Broker、To ## 典型拓扑结构 -
+
Kafka 集群包含若干个 Producer,若干个 Broker (Kafka 集群支持水平扩展,一般 Broker 数量越多,整个 Kafka 集群的吞吐量也就越高),若干个 Consumer Group,以及一个 Zookeeper 集群。 @@ -142,7 +142,7 @@ Producer 使用 Push 模式将消息发布到 Broker 上,Consumer 使用 Pull ## Kafka 数据流 -
+
Producers 往 Brokers 中指定的 Topic Push 消息,Consumers 从 Brokers 里面 Pull 指定 Topic 的消息,然后进行业务处理。 @@ -165,13 +165,13 @@ Segment 数据文件会首先被存储在内存中,当 Segment 上的消息条 Kafka 为每个 Segment 数据文件都建立了索引文件,索引文件的文件名与数据文件的文件名一致,不同的是索引文件的扩展名为 .index。比如: -
+
Segment 索引文件索引文件并不会为数据文件中的每条 Message 都建立索引,而是采用系数索引的方式,每个一定字节建立一条索引。这样可有效降低索引文件大小,方便将索引文件加载到内存中,提高集群的吞吐量。 如下图所示,000000000000036869.index 文件中记录了 (3,497) ,在数据文件中表示第 3 个 Message(在全局Partition 表示第 368772 个 Message),该 Message 的物理偏移地址为 497。 -
+
## Partition 中通过 Offset 查找 Message @@ -316,13 +316,13 @@ Kafka 消息存储时依赖于**文件系统**。为了利用数据的**局部 普通的数据拷贝 read & write: -
+
零拷贝主要的任务是**避免 CPU 做大量的数据拷贝任务,减少不必要的拷贝**。 **内存映射文件(Memory Mapped Files,mmap)**在 64 位操作系统中一般可以表示 20G 的数据文件,它的工作原理是直接利用操作系统的页缓存来实现文件到物理内存的直接映射。 -
+
显然,使用 mmap 替代 read 很明显减少了 1 次拷贝,当拷贝数据量很大时,无疑提升了效率。 diff --git a/docs/Kafka&RabbitMQ/RabbitMQ.md b/docs/Kafka&RabbitMQ/RabbitMQ.md index 583bb86..45ae273 100644 --- a/docs/Kafka&RabbitMQ/RabbitMQ.md +++ b/docs/Kafka&RabbitMQ/RabbitMQ.md @@ -25,7 +25,7 @@ AMQP (Advanced Message Queuing Protocol) 即高级消息队列协议,是一个 ## AMQP 模型 -
+
工作过程如下:首先发布者(Publisher)发布消息(Message),经由交换机 Exchange。交换机根据**路由规则**将收到的消息分发给与该交换机绑定的 Queue。最后 AMQP 代理会将消息投递给订阅了此队列的消费者,或者消费者按照需求自行获取。 @@ -66,7 +66,7 @@ Exchange 有以下 4 种类型,不同的类型对应着不同的路由策略 Exchange 默认类型。**路由规则是把消息路由到 Bindingkey 与 RoutingKey 完全匹配的 Queue 中**。direct 类型常用在**处理有优先级的任务**,根据任务的优先级把消息发送到对应的队列,这样可以指派更多的资源去处理高优先级的队列。 -
+
以上图为例,如果发送消息的时候 RoutingKey="booking",那么消息会路由到 Queue1 和 Queue2。如果在发送消息的时候设置 RoutingKey="create" 或 "confirm",消息只会路由到Queue2。如果以其他的 RoutingKey 发送消息,则消息不会路由到这两个队列中。 @@ -84,7 +84,7 @@ topic 类型的 Exchange 在匹配规则上进行了扩展,它与 direct 类 - BindingKey 和 RoutingKey 一样也是点号 `.` 分隔的字符串; - BindingKey 中可以存在两种特殊字符串 `*` 和 `#`,用于做模糊匹配,其中 `*` 用于匹配一个单词, `#` 用于匹配零个或多个单词。 -
+
以上图为例,如果发送消息的时候 RoutingKey 为 @@ -181,7 +181,7 @@ AMQP 的消息除属性外,也含有一个有效载荷 Payload(消息实际 # 三、RabbitMQ 命令行操作 -
+
## 启动 & 停止服务器 @@ -939,7 +939,7 @@ public class Consumer { 消息落库,对消息状态进行打标。 -
+
@@ -947,7 +947,7 @@ public class Consumer { 消息的延迟投递,做二次确认,回调检查。 -
+
@@ -967,7 +967,7 @@ public class Consumer { 消息的确认是指生产者投递消息后,如果 Broker 收到消息,则会给生产者一个应答,生产者进行接收应答,用来确定这条消息是否正常地发送到 Broker。 -
+
实现机制: @@ -1122,7 +1122,7 @@ public class Consumer { -
+
diff --git "a/docs/MySQL/1_\351\224\201\346\234\272\345\210\266.md" "b/docs/MySQL/1_\351\224\201\346\234\272\345\210\266.md" index 308ff73..d399881 100644 --- "a/docs/MySQL/1_\351\224\201\346\234\272\345\210\266.md" +++ "b/docs/MySQL/1_\351\224\201\346\234\272\345\210\266.md" @@ -50,7 +50,7 @@ - 会出现死锁 - 锁定粒度介于表锁和行锁之间,并发度一般 -
+
diff --git "a/docs/MySQL/2_\344\272\213\345\212\241\351\232\224\347\246\273\347\272\247\345\210\253\345\256\236\347\216\260.md" "b/docs/MySQL/2_\344\272\213\345\212\241\351\232\224\347\246\273\347\272\247\345\210\253\345\256\236\347\216\260.md" index 1d34445..575e058 100644 --- "a/docs/MySQL/2_\344\272\213\345\212\241\351\232\224\347\246\273\347\272\247\345\210\253\345\256\236\347\216\260.md" +++ "b/docs/MySQL/2_\344\272\213\345\212\241\351\232\224\347\246\273\347\272\247\345\210\253\345\256\236\347\216\260.md" @@ -32,7 +32,7 @@ UPDATE name SET name="c" WHERE id=1; 因为没有使用 `START TRANSACTION` 将上面的操作当成一个事务来执行,根据 MySQL 的 AUTOCOMMIT 机制,每个操作都会被当成一个事务来执行,所以上面的操作总共涉及到三个事务。 -
+
undo log 主要有两个作用: @@ -79,7 +79,7 @@ InnoDB 存储引擎在开启一个新事务后,执行每个 select 语句前 事务可见性示意图: -
+
### 快照读 & 当前读 @@ -159,7 +159,7 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE; 如下图所示: -
+
### 几个问题 @@ -179,7 +179,7 @@ delete from tb where id = 9 根据 id=9 条件定位,此时给 id = 9 的索引加上记录锁,根据 name 值(name是主键)到主索引中检索获得记录,再给该记录加上记录锁。 -
+
> 问题二:间隙锁是否用在非唯一索引的当前读中? @@ -191,7 +191,7 @@ delete from tb1 where id = 9 -- key 是非唯一索引 ``` -
+
可以看出,在 (6,9]、(9,11] 加了间隙锁。 @@ -205,7 +205,7 @@ delete from tb2 where id = 9 -- 没有为 id 建立索引 ``` -
+
此时对所有的间隙都上锁(功能上相当于锁表)。 diff --git "a/docs/MySQL/3_\347\264\242\345\274\225.md" "b/docs/MySQL/3_\347\264\242\345\274\225.md" index d8b1fa1..b08a6dd 100644 --- "a/docs/MySQL/3_\347\264\242\345\274\225.md" +++ "b/docs/MySQL/3_\347\264\242\345\274\225.md" @@ -55,7 +55,7 @@ c)非叶子节点的指针:P[1],P[2],... ,P[M];其中 P[1] 指向关键字小于 K[1] 的子树,P[M] 指向关键字大于 K[M-1] 的子树,其他 P[i] 关键字属于(K[i-1],K[i]) 的子树 -
+
### B+ 树 @@ -69,7 +69,7 @@ B+ 树是 B 树的变体,其定义基本与 B 树相同,除了: - 所有叶子节点均有一个链指针指向下一个叶子节点 -
+
数据库系统普遍采用 B+ 树作为索引结构,主要有以下原因: @@ -110,7 +110,7 @@ MySQL 索引使用的是 B 树中的 B+ 树,但索引是在存储引擎层实 MyISAM 引擎使用 B+ 树作索引结构,**叶子节点的 data 域存放的是数据记录的地址**,所有索引均是非聚集索引。 -
+
上图是一个 MyISAM 表的主索引(Primary key)示意图。 @@ -118,7 +118,7 @@ MyISAM 引擎使用 B+ 树作索引结构,**叶子节点的 data 域存放的 在 MyISAM 中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求 key 是唯一的,而辅助索引的 **key 可以重复**。如果在 Col2 上建立一个辅助索引,则该辅助索引的结构如下: -
+
同样也是一棵 B+ 树,data 域保存数据记录的地址。 @@ -130,7 +130,7 @@ InnoDB 也使用 B+ 树作为索引结构。有且仅有一个聚集索引,和 InnoDB 的数据文件本身就是索引文件。MyISAM 索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在 InnoDB 中,表数据文件本身就是按 B+ 树组织的一个索引结构,这棵树的**叶子节点 data 域保存了完整的数据记录**。这个索引的 key 是数据表的主键,因此 **InnoDB 表数据文件本身就是主索引**。 -
+
上图是 InnoDB 主索引(同时也是数据文件)的示意图。可以看到叶子节点包含了完整的数据记录。 @@ -142,7 +142,7 @@ InnoDB 的数据文件本身就是索引文件。MyISAM 索引文件和数据文 与 MyISAM 索引的不同是 **InnoDB 的辅助索引 data 域存储相应记录主键的值**而不是地址。例如,定义在 Col3 上的一个辅助索引: -
+
diff --git "a/docs/MySQL/4_MySQL\346\236\266\346\236\204.md" "b/docs/MySQL/4_MySQL\346\236\266\346\236\204.md" index eea5bfd..38a768d 100644 --- "a/docs/MySQL/4_MySQL\346\236\266\346\236\204.md" +++ "b/docs/MySQL/4_MySQL\346\236\266\346\236\204.md" @@ -12,7 +12,7 @@ 主要负责数据的存储和读取,采用可以替换的插件式架构,支持 InnoDB、MyISAM、Memory 等多个存储引擎,其中 InnoDB 引擎有自有的日志模块 redolog 模块。**现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始就被当做默认存储引擎了**。 -
+
diff --git "a/docs/MySQL/5_MySQL\344\274\230\345\214\226.md" "b/docs/MySQL/5_MySQL\344\274\230\345\214\226.md" index 339723d..d470d53 100644 --- "a/docs/MySQL/5_MySQL\344\274\230\345\214\226.md" +++ "b/docs/MySQL/5_MySQL\344\274\230\345\214\226.md" @@ -1,4 +1,4 @@ -# MySQL 优化 +# MySQL 调优 ## SQL 语句优化 diff --git "a/docs/OO/2_\345\210\233\345\273\272\345\236\213.md" "b/docs/OO/2_\345\210\233\345\273\272\345\236\213.md" index 35a293b..27f2ac5 100644 --- "a/docs/OO/2_\345\210\233\345\273\272\345\236\213.md" +++ "b/docs/OO/2_\345\210\233\345\273\272\345\236\213.md" @@ -12,7 +12,7 @@ 私有构造函数保证了不能通过构造函数来创建对象实例,只能通过公有静态函数返回唯一的私有静态变量。 -

+

### Implementation @@ -279,7 +279,7 @@ public class Singleton { 客户类往往有多个,如果不使用简单工厂,那么所有的客户类都要知道所有子类的细节。而且一旦子类发生改变,例如增加子类,那么所有的客户类都要进行修改。 -

+

### Implementation @@ -376,7 +376,7 @@ public class Client { 下图中,Factory 有一个 doSomething() 方法,这个方法需要用到一个产品对象,这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。 -

+

### Implementation @@ -440,7 +440,7 @@ public class ConcreteFactory2 extends Factory { 从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory,而工厂方法模式使用了继承。 -

+

### Implementation @@ -536,7 +536,7 @@ public class Client { 当然,光有指导者是不够的,必须要有能具体实现每步的对象,在生成器模式中称这些实现对象为**生成器**。 这样一来,**指导者就是可以重用的构建过程,而生成器是可以被切换的具体实现**。 -

+

### Implementation1 @@ -746,7 +746,7 @@ public class Client { 生成器的调用顺序: -

+

### Implementation2 @@ -836,7 +836,7 @@ abcdefghijklmnopqrstuvwxyz ### Class Diagram -

+

### Implementation diff --git "a/docs/OO/3_\350\241\214\344\270\272\345\236\213.md" "b/docs/OO/3_\350\241\214\344\270\272\345\236\213.md" index 9b5f828..e91dd3c 100644 --- "a/docs/OO/3_\350\241\214\344\270\272\345\236\213.md" +++ "b/docs/OO/3_\350\241\214\344\270\272\345\236\213.md" @@ -11,7 +11,7 @@ - Handler:定义处理请求的接口,并且实现后继链(successor) -

+

### Implementation @@ -158,7 +158,7 @@ request-2 is handle by ConcreteHandler2 - Invoker:通过它来调用命令 - Client:可以设置命令与命令的接收者 -

+

### Implementation1 ```java @@ -232,7 +232,7 @@ public class Client { 设计一个遥控器,可以控制电灯开关。 -

+

```java public interface Command { @@ -349,7 +349,7 @@ public class Client { - TerminalExpression:终结符表达式,每个终结符都需要一个 TerminalExpression。 - Context:上下文,包含解释器之外的一些全局信息。 -

+

### Implementation @@ -482,7 +482,7 @@ false - Iterator 主要定义了 hasNext() 和 next() 方法。 - Client 组合了 Aggregate,为了迭代遍历 Aggregate,也需要组合 Iterator。 -

+

### Implementation @@ -571,17 +571,17 @@ public class Client { - Mediator:中介者,定义一个接口用于与各同事(Colleague)对象通信。 - Colleague:同事,相关对象 -

+

### Implementation Alarm(闹钟)、CoffeePot(咖啡壶)、Calendar(日历)、Sprinkler(喷头)是一组相关的对象,在某个对象的事件产生时需要去操作其它对象,形成了下面这种依赖结构: -

+

使用中介者模式可以将复杂的依赖结构变成星形结构: -

+

```java public abstract class Colleague { @@ -744,7 +744,7 @@ doSprinkler() 备忘录实际上有两个接口,一个是提供给 Caretaker 的窄接口:它只能将备忘录传递给其它对象; 一个是提供给 Originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 Originator 访问本备忘录的内部状态。 -

+

### Implementation @@ -916,7 +916,7 @@ public class Client { 主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。 -

+

### Class Diagram @@ -924,13 +924,13 @@ public class Client { 观察者(Observer)的注册功能需要调用主题的 registerObserver() 方法。 -

+

### Implementation 天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。 -

+

```java public interface Subject { @@ -1059,7 +1059,7 @@ State:状态接口,用来封装与上下文的**一个特定状态所对应 ConcreteState:具体实现状态处理的类,每个类实现一个跟上下文相关的状态的具体处理。 -

+

### Implementation1 实现在线投票: @@ -1080,7 +1080,7 @@ ConcreteState:具体实现状态处理的类,每个类实现一个跟上下 程序结构如下图: -

+

```java /** @@ -1213,7 +1213,7 @@ public class Client { 糖果销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。 -

+

```java public interface State { @@ -1514,7 +1514,7 @@ No gumball dispensed - Strategy 接口定义了一个算法族,它们都实现了 behavior() 方法。 - Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior(),setStrategy(Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。 -

+

### 与状态模式的比较 @@ -1535,7 +1535,7 @@ No gumball dispensed 2. 对老客户报的价格,根据客户年限,给予一定的折扣 3. 对大客户报的价格,根据大客户的累计消费金额,给予一定的折扣 -

+

```java /** @@ -1702,13 +1702,13 @@ squeak! ### Class Diagram -

+

### Implementation 冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。 -

+

```java public abstract class CaffeineBeverage { @@ -1805,7 +1805,7 @@ Tea.addCondiments - ConcreteVisitor:具体访问者,存储遍历过程中的累计结果 - ObjectStructure:对象结构,可以是组合结构,或者是一个集合。 -

+

### Implementation @@ -2010,7 +2010,7 @@ Number of items: 6 ### Class Diagram -

+

### Implementation diff --git "a/docs/OO/4_\347\273\223\346\236\204\345\236\213.md" "b/docs/OO/4_\347\273\223\346\236\204\345\236\213.md" index 4839eb5..f3144f5 100644 --- "a/docs/OO/4_\347\273\223\346\236\204\345\236\213.md" +++ "b/docs/OO/4_\347\273\223\346\236\204\345\236\213.md" @@ -6,7 +6,7 @@ 把一个类接口转换成另一个用户需要的接口。 -

+

### Class Diagram Target:定义客户端需要的跟特定领域相关的接口。 @@ -16,7 +16,7 @@ Adaptee:已经存在的接口,通常能满足客户端的功能要求, Adapter:适配器,把Adaptee适配成为Client需要的Target。 -

+

### Implementation1 美国的电饭煲是在电压为 110V 下工作,而中国的电饭煲在电压 220V 下工作。要求将在美国使用的电饭煲适配成能在中国使用。 @@ -182,7 +182,7 @@ public class Client { - Abstraction:定义抽象类的接口 - Implementor:定义实现类接口 -

+

### Implementation @@ -343,7 +343,7 @@ Composite:组合对象,通常会存储子组件,定义包含子组件的 组合对象拥有一个或者多个组件对象,因此组合对象的操作可以委托给组件对象去处理,而组件对象可以是另一个组合对象或者叶子对象。 -

+

### Implementation1 商品类别树的管理,比如有如下所示的商品类别树: @@ -640,7 +640,7 @@ public class Client { 装饰者(Decorator)和具体组件(ConcreteComponent)都继承自组件(Component),具体组件的方法实现不需要依赖于其它对象,而装饰者组合了一个组件,这样它可以装饰其它装饰者或者具体组件。所谓装饰,就是把这个装饰者套在被装饰者之上,从而动态扩展被装饰者的功能。装饰者的方法有一部分是自己的,这属于它的功能,然后调用被装饰者的方法实现,从而也保留了被装饰者的功能。可以看到,具体组件应当是装饰层次的最低层,因为只有具体组件的方法实现不需要依赖于其它对象。 -

+

### Implementation1 给普通手机装饰上彩铃等功能。 @@ -778,7 +778,7 @@ IPhone打电话 下图表示在 DarkRoast 饮料上新增新添加 Mocha 配料,之后又添加了 Whip 配料。DarkRoast 被 Mocha 包裹,Mocha 又被 Whip 包裹。它们都继承自相同父类,都有 cost() 方法,外层类的 cost() 方法调用了内层类的 cost() 方法。 -

+

```java public interface Beverage { @@ -883,7 +883,7 @@ public class Client { ### Class Diagram -

+

### Implementation @@ -942,7 +942,7 @@ public class Client { - IntrinsicState:内部状态,享元对象共享内部状态 - ExtrinsicState:外部状态,每个享元对象的外部状态不同 -

+

### Implementation @@ -1042,7 +1042,7 @@ Java 利用缓存来加速大量小对象的访问时间。 - RealSubject:具体的目标对象,真正实现目标接口要求的功能。 -

+

### Implementation diff --git "a/docs/OO/6_\345\205\263\347\263\273\347\261\273\345\233\276.md" "b/docs/OO/6_\345\205\263\347\263\273\347\261\273\345\233\276.md" index f7c1fa1..a0532ac 100644 --- "a/docs/OO/6_\345\205\263\347\263\273\347\261\273\345\233\276.md" +++ "b/docs/OO/6_\345\205\263\347\263\273\347\261\273\345\233\276.md" @@ -6,7 +6,7 @@ 用来描述继承关系,在 Java 中使用 extends 关键字。 -

+

```text @startuml @@ -27,7 +27,7 @@ Vihical <|-- Trunck 用来实现一个接口,在 Java 中使用 implements 关键字。 -

+

```text @startuml @@ -48,7 +48,7 @@ MoveBehavior <|.. Run 表示整体由部分组成,但是整体和部分不是强依赖的,整体不存在了部分还是会存在。 -

+

```text @startuml @@ -71,7 +71,7 @@ Computer o-- Screen 和聚合不同,组合中整体和部分是强依赖的,整体不存在了部分也不存在了。比如公司和部门,公司没了部门就不存在了。但是公司和员工就属于聚合关系了,因为公司没了员工还在。 -

+

```text @startuml @@ -92,7 +92,7 @@ Company *-- DepartmentB 表示不同类对象之间有关联,这是一种静态关系,与运行过程的状态无关,在最开始就可以确定。因此也可以用 1 对 1、多对 1、多对多这种关联关系来表示。比如学生和学校就是一种关联关系,一个学校可以有很多学生,但是一个学生只属于一个学校,因此这是一种多对一的关系,在运行开始之前就可以确定。 -

+

```text @startuml @@ -115,7 +115,7 @@ School "1" - "n" Student - A 类是 B 类方法当中的一个参数; - A 类向 B 类发送消息,从而影响 B 类发生变化。 -

+

```text @startuml diff --git "a/docs/Redis/3_\345\215\225\347\272\277\347\250\213\346\250\241\345\236\213.md" "b/docs/Redis/3_\345\215\225\347\272\277\347\250\213\346\250\241\345\236\213.md" index 70ace34..50cd7fd 100644 --- "a/docs/Redis/3_\345\215\225\347\272\277\347\250\213\346\250\241\345\236\213.md" +++ "b/docs/Redis/3_\345\215\225\347\272\277\347\250\213\346\250\241\345\236\213.md" @@ -12,7 +12,7 @@ Redis 基于 Reactor 模式开发了自己的网络事件处理器,这个处 多路复用主要有三种技术:select,poll,epoll。epoll 是最新的也是目前最好的多路复用技术。 -
+
### 文件事件处理器 @@ -92,7 +92,7 @@ io-threads 2 # 官网建议 4 核的机器建议设置为2或3个线程,8 核 - 要么同时在读 Socket,要么同时在写,不会同时读或写 - 只负责读写 Socket 解析命令,不负责命令处理 -
+
### Redis 6.0 多线程和 Memcached 多线程模型对比 diff --git "a/docs/Redis/5_\346\214\201\344\271\205\345\214\226\346\234\272\345\210\266.md" "b/docs/Redis/5_\346\214\201\344\271\205\345\214\226\346\234\272\345\210\266.md" index 67093b6..ded7190 100644 --- "a/docs/Redis/5_\346\214\201\344\271\205\345\214\226\346\234\272\345\210\266.md" +++ "b/docs/Redis/5_\346\214\201\344\271\205\345\214\226\346\234\272\345\210\266.md" @@ -89,7 +89,7 @@ AOF 持久化存在的问题: BGREWRITEAOF 原理: -
+
Redis 维护一个 AOF 重写缓冲区(aof_rewrite_buf)。在子进程创建新的 AOF 文件期间,记录服务器执行的所有写命令。当子进程完成创建新 AOF 文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新 AOF 文件的末尾,使得新旧两个 AOF 文件所保存的数据库状态一致。最后,服务器用新的 AOF 文件替换旧的 AOF 文件,以此来完成 AOF 文件重写操作。 diff --git "a/docs/Redis/7_\347\274\223\345\255\230\351\227\256\351\242\230.md" "b/docs/Redis/7_\347\274\223\345\255\230\351\227\256\351\242\230.md" index 0a4470e..509860c 100644 --- "a/docs/Redis/7_\347\274\223\345\255\230\351\227\256\351\242\230.md" +++ "b/docs/Redis/7_\347\274\223\345\255\230\351\227\256\351\242\230.md" @@ -54,7 +54,7 @@ 可以令 k 和 m 都大一些会使得误判率降低,但是这会带来更高的时间和空间开销。 -
+
补充:[布隆过滤器详解](https://github.com/Snailclimb/JavaGuide/blob/master/docs/cs-basics/data-structure/bloom-filter.md) diff --git "a/docs/Redis/8_\351\203\250\347\275\262\346\226\271\345\274\217.md" "b/docs/Redis/8_\351\203\250\347\275\262\346\226\271\345\274\217.md" index 80f6e77..744745c 100644 --- "a/docs/Redis/8_\351\203\250\347\275\262\346\226\271\345\274\217.md" +++ "b/docs/Redis/8_\351\203\250\347\275\262\346\226\271\345\274\217.md" @@ -10,7 +10,7 @@ Redis 有以下 4 种部署方式: 单机的 Redis,能够承载的 QPS 大概就在上万到几万不等。对于主从架构,增加 Slave 节点的数量可以使得 Redis的 QPS 达到 10 万以上。 -
+
## 主从同步方法 @@ -32,7 +32,7 @@ Slave 节点同步数据的时候不会影响 Master 节点的正常工作,也 在整个快照同步进行的过程中,Master 节点的 buffer 仍在往前移动,如果快照同步的时间过长或者 buffer 太小,同步期间的增量指令在 buffer 中被覆盖,这样就会导致快照同步完成后无法进行增量复制,然后会再次发起快照同步,如此极有可能会陷入快照同步的死循环。所以需要配置一个合适的 buffer 大小参数,避免快照复制的死循环。 -
+
### 无盘复制 @@ -95,7 +95,7 @@ Redis 从 2.8 开始正式提供了 **哨兵 (sentinel) 架构**来解决这个 Redis 中多个 sentinel 组成**分布式架构**,持续监控主从节点的健康状况,当 Master 节点挂掉时,自动选择一个最优的 Slave 节点切换为 Master 节点。客户端在连接集群时,会先连接 sentinel,通过 sentinel 来查询 Master 节点的地址,然后再去连接 Master 节点进行数据交互。当 Master 节点发生故障时,客户端会重新向 sentinel 获取地址,sentinel 会将最新的 Master 节点地址告诉客户端,这样应用程序将无需重启即可自动完成节点切换。 -
+
sentinel 集群在 Redis 主从架构高可用中起到的 4 个作用: @@ -242,7 +242,7 @@ Master 至少有 1 个 slave,数据复制和同步的延迟不能超过 10 秒 Redis Cluster 是 Redis 的**分布式解决方案**,Redis 3.0 正式推出,解决单Master 架构的内存、并发、流量等瓶颈,以达到负载均衡的目的。 -
+
Redis cluster 适用于海量数据、高并发、高可用场景,在 Redis Cluster 架构中: @@ -270,7 +270,7 @@ Redis cluster 适用于海量数据、高并发、高可用场景,在 Redis Cl 例如有 Object A、Object B、Object C、Object D 四个数据对象,经过哈希计算后,在哈希环上的位置如下: -
+
根据一致性 Hash 算法:Object A 会被定位到 Node A 上;Object B 会被定位到 Node B 上;Object C 会被定位到 Node C 上;Object D 会被定位到 Node D 上。 @@ -278,11 +278,11 @@ Redis cluster 适用于海量数据、高并发、高可用场景,在 Redis Cl 例如删除节点 C,只需将 C 上的数据分布到节点 D 即可。 -
+
例如新增节点 X,只需要将它前一个节点 C 上的数据重新进行分布即可,对于节点 A、B、D 都没有影响。 -
+
综上所述,一致性 Hash 算法对于节点的增减都只需**重定位哈希环中的一小部分数据**,具有**较好的容错性和可扩展性**。 @@ -296,7 +296,7 @@ Redis cluster 适用于海量数据、高并发、高可用场景,在 Redis Cl 一致性哈希存在数据分布不均匀的问题,节点存储的数据量有可能会存在很大的不同。数据不均匀主要是因为节点在哈希环上分布的不均匀,这种情况在节点数量很少的情况下尤其明显。 -
+
解决方式是通过增加虚拟节点,然后将虚拟节点映射到真实节点上。虚拟节点的数量比真实节点来得多,那么虚拟节点在哈希环上分布的均匀性就会比原来的真实节点好,从而使得数据分布也更加均匀。 @@ -305,7 +305,7 @@ Redis cluster 适用于海量数据、高并发、高可用场景,在 Redis Cl - Node A 的 3 个虚拟节点:"Node A#1"、"Node A#2"、"Node A#3" - Node B 的 3 个虚拟节点:"Node B#1"、"Node B#2"、"Node B#3" -
+
同时**数据定位算法不变**,只是多了一步虚拟节点到实际节点的映射过程,例如"Node A#1"、"Node A#2"、"Node A#3" 这 3 个虚拟节点的数据均定位到 Node A 上,解决了服务节点少时数据倾斜的问题。在实际应用中,通常将虚拟节点数设置为 32 甚至更大,因此即使很少的服务节点也能做到相对均匀的数据分布。 diff --git "a/docs/Redis/9_\345\256\236\346\210\230.md" "b/docs/Redis/9_\345\256\236\346\210\230.md" index 10bb4bd..3759be9 100644 --- "a/docs/Redis/9_\345\256\236\346\210\230.md" +++ "b/docs/Redis/9_\345\256\236\346\210\230.md" @@ -10,7 +10,7 @@ 文章包括标题、作者、赞数等信息,在关系型数据库中很容易构建一张表来存储这些信息,在 Redis 中可以使用 HASH 来存储每种信息以及其对应的值的映射。 -
+
## 点赞功能实现 @@ -18,15 +18,15 @@ 为了节约内存,规定一篇文章发布满一周之后,就不能再对它进行投票,而文章的已投票集合也会被删除,可以为文章的已投票集合设置一个一周的过期时间就能实现这个规定。 -
+
## 对文章进行排序 为了按发布时间和点赞数进行排序,可以建立一个文章发布时间的有序集合和一个文章点赞数的有序集合。(下图中的 score 就是这里所说的点赞数;下面所示的有序集合分值并不直接是时间和点赞数,而是根据时间和点赞数间接计算出来的) -
+
115423 号用户给 100408 号文章投票的时候,数据结构发生的变化: -
+
diff --git a/docs/Safety/Cookie_Session_Token.md b/docs/Safety/Cookie_Session_Token.md index 2a16e77..617051a 100644 --- a/docs/Safety/Cookie_Session_Token.md +++ b/docs/Safety/Cookie_Session_Token.md @@ -63,7 +63,7 @@ Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足 - 1. **客户端发送一个http请求到服务器端,其中包含Cookie头部** - 1. **服务器端发送一个http响应到客户端** -
+
在客户端的第二次请求中包含Cookie头部,提供给了服务器端可以用来唯一标识客户端身份的信息。 这时,服务器端也就可以判断客户端是否启用了cookie。 diff --git "a/docs/Safety/\345\270\270\350\247\201\346\224\273\345\207\273\346\212\200\346\234\257\345\217\212\351\230\262\345\276\241.md" "b/docs/Safety/\345\270\270\350\247\201\346\224\273\345\207\273\346\212\200\346\234\257\345\217\212\351\230\262\345\276\241.md" index c478ac7..c63adaf 100644 --- "a/docs/Safety/\345\270\270\350\247\201\346\224\273\345\207\273\346\212\200\346\234\257\345\217\212\351\230\262\345\276\241.md" +++ "b/docs/Safety/\345\270\270\350\247\201\346\224\273\345\207\273\346\212\200\346\234\257\345\217\212\351\230\262\345\276\241.md" @@ -8,7 +8,7 @@ ## 攻击原理 -
+
@@ -194,7 +194,7 @@ XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用 ## 攻击原理 -
+
- 用户登录 A 网站 - A 网站确认身份 diff --git "a/docs/Spring/2_SpringIoC\345\216\237\347\220\206.md" "b/docs/Spring/2_SpringIoC\345\216\237\347\220\206.md" index 52185cf..875edb5 100644 --- "a/docs/Spring/2_SpringIoC\345\216\237\347\220\206.md" +++ "b/docs/Spring/2_SpringIoC\345\216\237\347\220\206.md" @@ -19,25 +19,25 @@ IOC,即控制反转(Inverse of Control)是一种**设计思想**,并不 可这样表示: -
+
相应代码代码: -
+
size 是固定值,可以进行相应的改进: -
+
**依赖注入设计思路**: 先设计行李箱的大概样子,再根据行李箱的样子设计箱体,根据箱体去设计底盘,然后去设计轮子。 -
+
相应代码如下: -
+
不难理解,依赖注入就是**将底层类作为参数传递给上层类,实现上层对下层的控制**。 @@ -145,7 +145,7 @@ public class ExampleBean { 依赖倒置原则、IoC、DI 和 IoC 容器的关系: -
+
补充:[控制反转-知乎解答](https://www.zhihu.com/question/23277575/answer/169698662) @@ -173,7 +173,7 @@ Spring IoC 容器的代表就是 `org.springframework.beans` 包下的 **BeanFac ### IoC 容器初始化过程 -
+
- Resource 定位:即 BeanDefinition 的资源定位,Resource 为各种形式的 BeanDefinition 的使用都提供了统一的接口 - BeanDefinition 的载入 @@ -181,7 +181,7 @@ Spring IoC 容器的代表就是 `org.springframework.beans` 包下的 **BeanFac ### Spring Bean 的装配流程 -
+
IoC 容器其实就是一个大工厂,它用来管理我们所有的对象以及依赖关系: @@ -325,7 +325,7 @@ globalSession 作用域**类似于标准的 HTTP session** 作用域, 不过 Spring bean 的生命周期执行如下图: -
+
1、Spring 对 Bean 进行实例化。 diff --git "a/docs/Spring/4_SpringMVC\345\216\237\347\220\206.md" "b/docs/Spring/4_SpringMVC\345\216\237\347\220\206.md" index e17ccce..42723ef 100644 --- "a/docs/Spring/4_SpringMVC\345\216\237\347\220\206.md" +++ "b/docs/Spring/4_SpringMVC\345\216\237\347\220\206.md" @@ -36,7 +36,7 @@ Spring MVC 框架是以请求为驱动,围绕 **DispatcherServlet** 设计, 原理图如下: -
+
- 客户端发起 HTTP 请求,将请求提交到 DispatcherServlet。 - 寻找处理器:由 DispatcherServlet 查询一个或多个 HandlerMapping,找到处理该请求的 Contoller。 diff --git a/docs/Spring/7_MyBatis.md b/docs/Spring/7_MyBatis.md index fd9e987..9c7e477 100644 --- a/docs/Spring/7_MyBatis.md +++ b/docs/Spring/7_MyBatis.md @@ -52,7 +52,7 @@ Mapper 接口的实例是从 SqlSession 中获取,作用是发送 SQL,然后 ## 功能架构 -
+
### 接口层 @@ -91,13 +91,13 @@ Mapper 接口的实例是从 SqlSession 中获取,作用是发送 SQL,然后 - MappedStatement 对 SQL 执行输出结果进行定义,包括 HashMap、基本类型、pojo,Executor 通过MappedStatement 在执行 SQL 后将输出结果映射至 Java对象中,输出结果映射过程相当于 jdbc 编程中对结果的解析处理过程。 -
+
## 缓存机制 MyBatis 的缓存分为一级缓存和二级缓存。默认情况下一级缓存是开启的。 -
+
### 一级缓存 diff --git "a/docs/Zookeeper/2_\346\225\260\346\215\256\346\250\241\345\236\213.md" "b/docs/Zookeeper/2_\346\225\260\346\215\256\346\250\241\345\236\213.md" index f92082c..045b82f 100644 --- "a/docs/Zookeeper/2_\346\225\260\346\215\256\346\250\241\345\236\213.md" +++ "b/docs/Zookeeper/2_\346\225\260\346\215\256\346\250\241\345\236\213.md" @@ -6,7 +6,7 @@ ZooKeeper 的每个节点不经存储了数据信息,同时提供对节点信 每个节点还可以拥有 N 个子节点,最上层是根节点以“/”来代表,Zookeeper 的数据模型如下图: -
+
## Znode 数据模型 diff --git "a/docs/Zookeeper/3_\345\216\237\347\220\206.md" "b/docs/Zookeeper/3_\345\216\237\347\220\206.md" index 4218d53..1c7db94 100644 --- "a/docs/Zookeeper/3_\345\216\237\347\220\206.md" +++ "b/docs/Zookeeper/3_\345\216\237\347\220\206.md" @@ -4,7 +4,7 @@ Zookeeper 是一个基于主从复制的高可用集群。通常 3 台服务器就可构成一个 ZooKeeper 集群。ZooKeeper 官方提供的架构图就是一个 ZooKeeper 集群整体对外提供服务。 -
+
每一个 Server 代表一个安装 ZooKeeper 服务的服务器,组成 ZooKeeper 服务的服务器都会在内存中维护当前的服务器状态,并且每台服务器之间都互相保持着通信。 @@ -34,7 +34,7 @@ Follower 在接收到一个客户端请求后会先判断该请求是读请求 Zookeeper 集群在运行过程中需要支持更多的客户端并发操作,就需要更多的服务实例,而更多的服务实例会使集群投票阶段变得复杂,集群选主时间过程,不利于集群故障快速恢复。因此,Zookeeper 中引入 Observer,Observer 不参与投票,但是接收来自客户端的连接并响应客户端的读请求,将写请求转发给 Leader。加入更多的 Observer节点,不仅提高了 Zookeeper 集群的吞吐量,也保障了系统的稳定性。 -
+
## ZAB 协议 @@ -133,7 +133,7 @@ ZAB 协议的 Java 实现与其定义略有不同,在实际实现时,选举 S5 提议自己为 Leader 并为自己投票,然后与 S1、S2、S3和 S4 交换投票结果,发现 S3 已经成为 Leader,S5 就成为 Follower。 -
+
## 关于 ZooKeeper 集群的几个问题 diff --git a/docs/_coverpage.md b/docs/_coverpage.md index a9419b8..1a7a868 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -1,4 +1,4 @@ -
+
@@ -25,4 +25,4 @@ 参考资料

-[开始阅读](./README.md) \ No newline at end of file +[开始阅读](./README.md) diff --git "a/docs/cluster/2_\351\233\206\347\276\244\344\270\213\347\232\204Session\347\256\241\347\220\206.md" "b/docs/cluster/2_\351\233\206\347\276\244\344\270\213\347\232\204Session\347\256\241\347\220\206.md" index a6803fe..2950e6c 100644 --- "a/docs/cluster/2_\351\233\206\347\276\244\344\270\213\347\232\204Session\347\256\241\347\220\206.md" +++ "b/docs/cluster/2_\351\233\206\347\276\244\344\270\213\347\232\204Session\347\256\241\347\220\206.md" @@ -1,2 +1,3 @@ # 集群下的 Session 管理 +待补充。 diff --git "a/docs/distribution/2_CAP\347\220\206\350\256\272.md" "b/docs/distribution/2_CAP\347\220\206\350\256\272.md" index 1cf1f8c..714a0a7 100644 --- "a/docs/distribution/2_CAP\347\220\206\350\256\272.md" +++ "b/docs/distribution/2_CAP\347\220\206\350\256\272.md" @@ -2,7 +2,7 @@ 分布式系统不可能同时满足一致性(C:Consistency)、可用性(A:Availability)和分区容忍性(P:Partition Tolerance),最多只能同时满足其中两项。 -
+
## 一致性(Consistency) diff --git "a/docs/distribution/3_\345\210\206\345\270\203\345\274\217\351\224\201.md" "b/docs/distribution/3_\345\210\206\345\270\203\345\274\217\351\224\201.md" index b3f9669..12cdc4b 100644 --- "a/docs/distribution/3_\345\210\206\345\270\203\345\274\217\351\224\201.md" +++ "b/docs/distribution/3_\345\210\206\345\270\203\345\274\217\351\224\201.md" @@ -45,7 +45,7 @@ EXPIRE 指令可以为一个键值对设置一个过期时间,从而避免了 -
+
@@ -57,7 +57,7 @@ EXPIRE 指令可以为一个键值对设置一个过期时间,从而避免了 Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点的父节点为 /app1。 -

+

### 2. 节点类型 diff --git "a/docs/distribution/4_\345\210\206\345\270\203\345\274\217\344\272\213\345\212\241.md" "b/docs/distribution/4_\345\210\206\345\270\203\345\274\217\344\272\213\345\212\241.md" index 928c412..86081dd 100644 --- "a/docs/distribution/4_\345\210\206\345\270\203\345\274\217\344\272\213\345\212\241.md" +++ "b/docs/distribution/4_\345\210\206\345\270\203\345\274\217\344\272\213\345\212\241.md" @@ -25,7 +25,7 @@ -

+

**阶段2:提交阶段(commit phase)** @@ -33,7 +33,7 @@ 需要注意的是,在准备阶段,参与者执行了事务,但是还未提交。只有在提交阶段接收到协调者发来的通知后,才进行提交或者回滚。 -

+

### 存在的问题 @@ -89,7 +89,7 @@ TCC 即补偿事务,其实就是采用的**补偿机制**,其核心思想是 3. 在分布式事务操作的另一方从消息队列中读取一个消息,并执行消息中的操作。 4. 如果是业务上面的失败,可以给生产方发送一个业务补偿消息,通知生产方进行回滚等操作。 -
+
这种方案遵循 BASE 理论,采用的是最终一致性,笔者认为是这几种方案里面比较适合实际业务场景的,即不会出现像 2PC 那样复杂的实现(当调用链很长的时候,2PC的可用性是非常低的),也不会像TCC那样可能出现确认或者回滚不了的情况。 diff --git a/docs/index.html b/docs/index.html index 5d0be96..018c63a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -6,7 +6,7 @@ - +