Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1649e98
单词修改:Extention ClassLoader => Extension ClassLoader
NoMindToThink Dec 4, 2020
2759e1b
[F] Missing markdown bold ** symbol in Java基础知识.md
VergeDX Dec 4, 2020
6ee3db6
Update 万字详解ThreadLocal关键字.md
Dec 7, 2020
fd11d51
Update 数据库索引.md
Xunzhuo Dec 8, 2020
8fe56a6
Merge branch 'master' into master
VergeDX Dec 10, 2020
f4fad2f
fix OSPF error
Xunzhuo Dec 11, 2020
19d31b1
fix markdown error
Xunzhuo Dec 12, 2020
6cc0e4c
Update java线程池学习总结.md
Xunzhuo Dec 13, 2020
40a6014
Update java线程池学习总结.md
Xunzhuo Dec 13, 2020
2c17d28
Update 事务隔离级别(图文详解).md
Xunzhuo Dec 13, 2020
4c080d2
Update 几道常见的链表算法题.md
Xunzhuo Dec 13, 2020
a636eb7
Update java-learning-path-and-methods.md
sleepingraven Dec 15, 2020
bb63e55
Update java-learning-website-blog.md
sleepingraven Dec 15, 2020
f478af0
Merge pull request #1015 from gi122281742/master
Snailclimb Dec 15, 2020
f89eff7
Merge pull request #1016 from VergeDX/master
Snailclimb Dec 15, 2020
262dceb
Merge pull request #1018 from shahainloong/master
Snailclimb Dec 15, 2020
98497d4
Merge pull request #1020 from Xunzhuo/patch-8
Snailclimb Dec 15, 2020
ebde4e6
Merge pull request #1023 from Xunzhuo/patch-9
Snailclimb Dec 15, 2020
fccb4a2
Merge pull request #1025 from Xunzhuo/patch-13
Snailclimb Dec 15, 2020
108860b
Merge pull request #1026 from Xunzhuo/patch-14
Snailclimb Dec 15, 2020
4fb63ea
Merge pull request #1027 from Xunzhuo/patch-15
Snailclimb Dec 15, 2020
ac6192b
Merge pull request #1028 from Xunzhuo/patch-16
Snailclimb Dec 15, 2020
2297f06
Merge pull request #1029 from Xunzhuo/patch-17
Snailclimb Dec 15, 2020
ffdc008
Merge pull request #1030 from sleepingraven/patch-1
Snailclimb Dec 15, 2020
be2decb
Update java-learning-path-and-methods.md
Snailclimb Dec 15, 2020
ccf2130
Merge pull request #1031 from sleepingraven/master
Snailclimb Dec 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ public class Solution {
**进阶——一次遍历法:**


> **链表中倒数第N个节点也就是正数第(L-N+1)个节点。
> 链表中倒数第N个节点也就是正数第(L-N+1)个节点。

其实这种方法就和我们上面第四题找“链表中倒数第k个节点”所用的思想是一样的。**基本思路就是:** 定义两个节点 node1、node2;node1 节点先跑,node1节点 跑到第 n+1 个节点的时候,node2 节点开始跑.当node1 节点跑到最后一个节点时,node2 节点所在的位置就是第 (L-n ) 个节点(L代表总链表长度,也就是倒数第 n+1 个节点)

Expand Down
6 changes: 3 additions & 3 deletions docs/database/事务隔离级别(图文详解).md
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ mysql> SELECT @@tx_isolation;
+-----------------+
```

这里需要注意的是:与 SQL 标准不同的地方在于InnoDB 存储引擎在 **REPEATABLE-READ(可重读)** 事务隔离级别下,允许应用使用 Next-Key Lock 锁算法来避免幻读的产生。这与其他数据库系统(如 SQL Server)是不同的。所以说虽然 InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)**,但是可以通过应用加锁读(例如 `select * from table for update` 语句)来保证不会产生幻读,而这个加锁度使用到的机制就是 Next-Key Lock 锁算法。从而达到了 SQL 标准的 **SERIALIZABLE(可串行化)** 隔离级别。
这里需要注意的是:与 SQL 标准不同的地方在于InnoDB 存储引擎在 **REPEATABLE-READ(可重读)** 事务隔离级别下,允许应用使用 Next-Key Lock 锁算法来避免幻读的产生。这与其他数据库系统(如 SQL Server)是不同的。所以说虽然 InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)** ,但是可以通过应用加锁读(例如 `select * from table for update` 语句)来保证不会产生幻读,而这个加锁度使用到的机制就是 Next-Key Lock 锁算法。从而达到了 SQL 标准的 **SERIALIZABLE(可串行化)** 隔离级别。

因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是**READ-COMMITTED(读取提交内容):**,但是你要知道的是InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)**并不会有任何性能损失。
因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是**READ-COMMITTED(读取提交内容):**,但是你要知道的是InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)** 并不会有任何性能损失。

InnoDB 存储引擎在 **分布式事务** 的情况下一般会用到**SERIALIZABLE(可串行化)**隔离级别。
InnoDB 存储引擎在 **分布式事务** 的情况下一般会用到**SERIALIZABLE(可串行化)** 隔离级别。

### 实际情况演示

Expand Down
6 changes: 3 additions & 3 deletions docs/database/数据库索引.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
## 为什么要用索引?索引的优缺点分析

### 索引的优点
**可以大大加快 数据的检索速度(大大减少的检索的数据量), 这也是创建索引的最主要的原因。毕竟大部分系统的读请求总是大于写请求的。 ** 另外,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
**可以大大加快 数据的检索速度(大大减少的检索的数据量), 这也是创建索引的最主要的原因。毕竟大部分系统的读请求总是大于写请求的。** 另外,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。

### 索引的缺点
1. **创建索引和维护索引需要耗费许多时间**:当对表中的数据进行增删改的时候,如果数据有索引,那么索引也需要动态的修改,会降低SQL执行效率。
Expand Down Expand Up @@ -58,7 +58,7 @@ B+树是有序的,在这种范围查询中,优势非常大,直接遍历比

**PS:不懂的同学可以暂存疑,慢慢往下看,后面会有答案的,也可以自行搜索。**

1. **唯一索引(Unique Key)** :唯一索引也是一种约束。**唯一索引的属性列不能出现重复的数据,但是允许数据为NULL,一张表允许创建多个唯一索引。**建立唯一索引的目的大部分时候都是为了该属性列的数据的唯一性,而不是为了查询效率。
1. **唯一索引(Unique Key)** :唯一索引也是一种约束。**唯一索引的属性列不能出现重复的数据,但是允许数据为NULL,一张表允许创建多个唯一索引。** 建立唯一索引的目的大部分时候都是为了该属性列的数据的唯一性,而不是为了查询效率。
2. **普通索引(Index)** :**普通索引的唯一作用就是为了快速查询数据,一张表允许创建多个普通索引,并允许数据重复和NULL。**
3. **前缀索引(Prefix)** :前缀索引只适用于字符串类型的数据。前缀索引是对文本的前几个字符创建索引,相比普通索引建立的数据更小,
因为只取前几个字符。
Expand Down Expand Up @@ -222,4 +222,4 @@ ALTER TABLE table ADD INDEX index_name (num,name,age)

### 使用索引一定能提高查询性能吗?

大多数情况下,索引查询都是比全表扫描要快的。但是如果数据库的数据量不大,那么使用索引也不一定能够带来很大提升。
大多数情况下,索引查询都是比全表扫描要快的。但是如果数据库的数据量不大,那么使用索引也不一定能够带来很大提升。
2 changes: 1 addition & 1 deletion docs/java/basis/Java基础知识.md
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ private static class CharacterCache {
}
```

两种浮点数类型的包装类 Float,Double 并没有实现常量池技术。\*\*
**两种浮点数类型的包装类 Float,Double 并没有实现常量池技术。**

```java
Integer i1 = 33;
Expand Down
2 changes: 1 addition & 1 deletion docs/java/jvm/[加餐]大白话带你认识JVM.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ GC将无用对象从内存中卸载
加载一个Class类的顺序也是有优先级的,类加载器从最底层开始往上的顺序是这样的

1. BootStrap ClassLoader:rt.jar
2. Extention ClassLoader: 加载扩展的jar包
2. Extension ClassLoader: 加载扩展的jar包
3. App ClassLoader:指定的classpath下面的jar包
4. Custom ClassLoader:自定义的类加载器

Expand Down
4 changes: 2 additions & 2 deletions docs/java/multi-thread/java线程池学习总结.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ pool-1-thread-2 End. Time = Sun Apr 12 11:14:47 CST 2020

现在,我们就分析上面的输出内容来简单分析一下线程池原理。

**为了搞懂线程池的原理,我们需要首先分析一下 `execute`方法。**在 4.1 节中的 Demo 中我们使用 `executor.execute(worker)`来提交一个任务到线程池中去,这个方法非常重要,下面我们来看看它的源码:
**为了搞懂线程池的原理,我们需要首先分析一下 `execute`方法。** 在 4.1 节中的 Demo 中我们使用 `executor.execute(worker)`来提交一个任务到线程池中去,这个方法非常重要,下面我们来看看它的源码:

```java
// 存放线程池的运行状态 (runState) 和线程池内有效线程的数量 (workerCount)
Expand Down Expand Up @@ -543,7 +543,7 @@ public interface Callable<V> {
#### 4.3.2 `execute()` vs `submit()`

1. **`execute()`方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;**
2. **`submit()`方法用于提交需要返回值的任务。线程池会返回一个 `Future` 类型的对象,通过这个 `Future` 对象可以判断任务是否执行成功**,并且可以通过 `Future` 的 `get()`方法来获取返回值,`get()`方法会阻塞当前线程直到任务完成,而使用 `get(long timeout,TimeUnit unit)`方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。
2. **`submit()`方法用于提交需要返回值的任务。线程池会返回一个 `Future` 类型的对象,通过这个 `Future` 对象可以判断任务是否执行成功** ,并且可以通过 `Future` 的 `get()`方法来获取返回值,`get()`方法会阻塞当前线程直到任务完成,而使用 `get(long timeout,TimeUnit unit)`方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。

我们以**`AbstractExecutorService`**接口中的一个 `submit` 方法为例子来看看源代码:

Expand Down
39 changes: 19 additions & 20 deletions docs/java/multi-thread/万字详解ThreadLocal关键字.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
public class ThreadLocalTest {
private List<String> messages = Lists.newArrayList();

public static final `ThreadLocal`<ThreadLocalTest> holder = `ThreadLocal`.withInitial(ThreadLocalTest::new);
public static final ThreadLocal<ThreadLocalTest> holder = ThreadLocal.withInitial(ThreadLocalTest::new);

public static void add(String message) {
holder.get().messages.add(message);
Expand Down Expand Up @@ -70,20 +70,19 @@ size: 0

![](./images/thread-local/2.png)


`Thread`类有一个类型为``ThreadLocal`.`ThreadLocalMap``的实例变量`threadLocals`,也就是说每个线程有一个自己的`ThreadLocalMap`。
`Thread`类有一个类型为`ThreadLocal.ThreadLocalMap`的实例变量`threadLocals`,也就是说每个线程有一个自己的`ThreadLocalMap`。

`ThreadLocalMap`有自己的独立实现,可以简单地将它的`key`视作`ThreadLocal`,`value`为代码中放入的值(实际上`key`并不是`ThreadLocal`本身,而是它的一个**弱引用**)。

每个线程在往`ThreadLocal`里放值的时候,都会往自己的`ThreadLocalMap`里存,读也是以`ThreadLocal`作为引用,在自己的`map`里找对应的`key`,从而实现了**线程隔离**。

`ThreadLocalMap`有点类似`HashMap`的结构,只是`HashMap`是由**数组+链表**实现的,而`ThreadLocalMap`中并没有**链表**结构。

我们还要注意`Entry`, 它的`key`是``ThreadLocal`<?> k` ,继承自`WeakReference, 也就是我们常说的弱引用类型。
我们还要注意`Entry`, 它的`key`是`ThreadLocal<?> k` ,继承自`WeakReference`, 也就是我们常说的弱引用类型。

### GC 之后key是否为null?

回应开头的那个问题, `ThreadLocal` 的`key`是弱引用,那么在` `ThreadLocal`.get()`的时候,发生`GC`之后,`key`是否是`null`?
回应开头的那个问题, `ThreadLocal` 的`key`是弱引用,那么在`ThreadLocal.get()`的时候,发生`GC`之后,`key`是否是`null`?

为了搞清楚这个问题,我们需要搞清楚`Java`的**四种引用类型**:

Expand All @@ -110,19 +109,19 @@ public class ThreadLocalDemo {

private static void test(String s,boolean isGC) {
try {
new `ThreadLocal`<>().set(s);
new ThreadLocal<>().set(s);
if (isGC) {
System.gc();
}
Thread t = Thread.currentThread();
Class<? extends Thread> clz = t.getClass();
Field field = clz.getDeclaredField("threadLocals");
field.setAccessible(true);
Object `ThreadLocalMap` = field.get(t);
Class<?> tlmClass = `ThreadLocalMap`.getClass();
Object ThreadLocalMap = field.get(t);
Class<?> tlmClass = ThreadLocalMap.getClass();
Field tableField = tlmClass.getDeclaredField("table");
tableField.setAccessible(true);
Object[] arr = (Object[]) tableField.get(`ThreadLocalMap`);
Object[] arr = (Object[]) tableField.get(ThreadLocalMap);
for (Object o : arr) {
if (o != null) {
Class<?> entryClass = o.getClass();
Expand All @@ -142,8 +141,8 @@ public class ThreadLocalDemo {

结果如下:
```java
弱引用key:java.lang.`ThreadLocal`@433619b6,值:abc
弱引用key:java.lang.`ThreadLocal`@418a15e3,值:java.lang.ref.SoftReference@bf97a12
弱引用key:java.lang.ThreadLocal@433619b6,值:abc
弱引用key:java.lang.ThreadLocal@418a15e3,值:java.lang.ref.SoftReference@bf97a12
--gc后--
弱引用key:null,值:def
```
Expand All @@ -162,7 +161,7 @@ new ThreadLocal<>().set(s);

这个问题刚开始看,如果没有过多思考,**弱引用**,还有**垃圾回收**,那么肯定会觉得是`null`。

其实是不对的,因为题目说的是在做 ``ThreadLocal`.get()` 操作,证明其实还是有**强引用**存在的,所以 `key` 并不为 `null`,如下图所示,`ThreadLocal`的**强引用**仍然是存在的。
其实是不对的,因为题目说的是在做 `ThreadLocal.get()` 操作,证明其实还是有**强引用**存在的,所以 `key` 并不为 `null`,如下图所示,`ThreadLocal`的**强引用**仍然是存在的。

![image.png](./images/thread-local/5.png)

Expand Down Expand Up @@ -217,8 +216,8 @@ public class ThreadLocal<T> {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}

static class `ThreadLocalMap` {
`ThreadLocalMap`(`ThreadLocal`<?> firstKey, Object firstValue) {
static class ThreadLocalMap {
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);

Expand All @@ -230,7 +229,7 @@ public class ThreadLocal<T> {
}
```

每当创建一个`ThreadLocal`对象,这个``ThreadLocal`.nextHashCode` 这个值就会增长 `0x61c88647` 。
每当创建一个`ThreadLocal`对象,这个`ThreadLocal.nextHashCode` 这个值就会增长 `0x61c88647` 。

这个值很特殊,它是**斐波那契数** 也叫 **黄金分割数**。`hash`增量为 这个数字,带来的好处就是 `hash` **分布非常均匀**。

Expand All @@ -244,7 +243,7 @@ public class ThreadLocal<T> {

> **注明:** 下面所有示例图中,**绿色块**`Entry`代表**正常数据**,**灰色块**代表`Entry`的`key`值为`null`,**已被垃圾回收**。**白色块**表示`Entry`为`null`。

虽然`ThreadLocalMap`中使用了**黄金分隔数来**作为`hash`计算因子,大大减少了`Hash`冲突的概率,但是仍然会存在冲突。
虽然`ThreadLocalMap`中使用了**黄金分割数来**作为`hash`计算因子,大大减少了`Hash`冲突的概率,但是仍然会存在冲突。

`HashMap`中解决冲突的方法是在数组上构造一个**链表**结构,冲突的数据挂载到链表上,如果链表长度超过一定数量则会转化成**红黑树**。

Expand Down Expand Up @@ -403,7 +402,7 @@ private static int prevIndex(int i, int len) {
`java.lang.ThreadLocal.ThreadLocalMap.replaceStaleEntry()`:

```java
private void replaceStaleEntry(`ThreadLocal`<?> key, Object value,
private void replaceStaleEntry(ThreadLocal<?> key, Object value,
int staleSlot) {
Entry[] tab = table;
int len = tab.length;
Expand Down Expand Up @@ -687,7 +686,7 @@ private void resize() {

![](./images/thread-local/27.png)

我们以`get(ThreadLocal1)`为例,通过`hash`计算后,正确的`slot`位置应该是4,而`index=4`的槽位已经有了数据,且`key`值不等于``ThreadLocal`1`,所以需要继续往后迭代查找。
我们以`get(ThreadLocal1)`为例,通过`hash`计算后,正确的`slot`位置应该是4,而`index=4`的槽位已经有了数据,且`key`值不等于`ThreadLocal1`,所以需要继续往后迭代查找。

迭代到`index=5`的数据时,此时`Entry.key=null`,触发一次探测式数据回收操作,执行`expungeStaleEntry()`方法,执行完后,`index 5,8`的数据都会被回收,而`index 6,7`的数据都会前移,此时继续往后迭代,到`index = 6`的时候即找到了`key`值相等的`Entry`数据,如下图所示:

Expand All @@ -698,7 +697,7 @@ private void resize() {
`java.lang.ThreadLocal.ThreadLocalMap.getEntry()`:

```java
private Entry getEntry(`ThreadLocal`<?> key) {
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
Expand All @@ -707,7 +706,7 @@ private Entry getEntry(`ThreadLocal`<?> key) {
return getEntryAfterMiss(key, i, e);
}

private Entry getEntryAfterMiss(`ThreadLocal`<?> key, int i, Entry e) {
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;

Expand Down
2 changes: 1 addition & 1 deletion docs/network/计算机网络.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ TCP的拥塞控制采用了四种算法,即 **慢开始** 、 **拥塞避免**

<img src="https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/url输入到展示出来的过程.jpg" style="zoom:50%;" />

> 上图有一个错误,请注意,是OSPF不是OPSF。 OSPF(Open Shortest Path Fitst,ospf)开放最短路径优先协议,是由Internet工程任务组开发的路由选择协议
> 上图有一个错误,请注意,是OSPF不是OPSF。 OSPF(Open Shortest Path First,ospf)开放最短路径优先协议,是由Internet工程任务组开发的路由选择协议

总体来说分为以下几个过程:

Expand Down
6 changes: 3 additions & 3 deletions docs/questions/java-learning-path-and-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
3. [【加餐】一些重要的Java程序设计题](https://snailclimb.gitee.io/javaguide/#/docs/java/Java程序设计题)
4. [【选看】J2EE 基础知识](https://snailclimb.gitee.io/javaguide/#/docs/java/J2EE基础知识)

> 我们的网站需要运行在“操作系统”之上(一般是部署在Linux系统),并且我们与网站的每次交互都需要经过“网络”,需要经历三次握手和四次挥手才能简历连接,需要HTTP才能发出请求已经拿到网站后台的相应。所以第二步,我推荐可以适当花时间看一下 **操作系统与计算机网络 方面的知识。** 但是,不做强求!你抽时间一定要补上就行!
> 我们的网站需要运行在“操作系统”之上(一般是部署在Linux系统),并且我们与网站的每次交互都需要经过“网络”,需要经历三次握手和四次挥手才能建立连接,需要HTTP才能发出请求已经拿到网站后台的相应。所以第二步,我推荐可以适当花时间看一下 **操作系统与计算机网络 方面的知识。** 但是,不做强求!你抽时间一定要补上就行!

### step 2(可选):操作系统与计算机网络

Expand Down Expand Up @@ -172,11 +172,11 @@

### step 10:深入学习

可以再回来看一下多线程方面的知识,还可以利用业余时间学习一下 **[NIO](https://github.com/Snailclimb/JavaGuide#io "NIO")** 和 **Netty** ,这样简历上也可以多点东西。如果想去大厂,**[JVM](https://github.com/Snailclimb/JavaGuide#jvm "JVM")** 的一些知识也是必学的(**Java 内存区域、虚拟机垃圾算法、虚拟垃圾收集器、JVM 内存管理**)推荐《深入理解 Java 虚拟机:JVM 高级特性与最佳实践(最新第二版》和《实战 Java 虚拟机》,如果嫌看书麻烦的话,你也可以看我整理的文档。
可以再回来看一下多线程方面的知识,还可以利用业余时间学习一下 **[NIO](https://github.com/Snailclimb/JavaGuide#io "NIO")** 和 **Netty** ,这样简历上也可以多点东西。如果想去大厂,**[JVM](https://github.com/Snailclimb/JavaGuide#jvm "JVM")** 的一些知识也是必学的(**Java 内存区域、虚拟机垃圾算法、虚拟垃圾收集器、JVM 内存管理**)推荐《深入理解 Java 虚拟机:JVM 高级特性与最佳实践(最新第二版)》和《实战 Java 虚拟机》,如果嫌看书麻烦的话,你也可以看我整理的文档。

另外,现在微服务特别火,很多公司在面试也明确要求需要微服务方面的知识。如果有精力的话可以去学一下 SpringCloud 生态系统微服务方面的东西。

> **微服务的概念庞大,技术种类也很多,但是目前大型互联网公司广泛采用的,**实话实话这些东西我不在行,自己没有真实做过微服务的项目。不过下面是我自己总结的一些关于微服务比价重要的知识,选学。
> **微服务的概念庞大,技术种类也很多,但是目前大型互联网公司广泛采用的,** 实话实话这些东西我不在行,自己没有真实做过微服务的项目。不过下面是我自己总结的一些关于微服务比价重要的知识,选学。

### step 11:微服务

Expand Down
Loading