From 61773d3d37fe7d0de6c9229fce1a018d7c1e7eb1 Mon Sep 17 00:00:00 2001 From: iMaGetLazyyy Date: Tue, 11 May 2021 16:49:31 +0800 Subject: [PATCH 1/4] =?UTF-8?q?fix=20typo=20=E5=86=97=E4=BD=99=E7=9A=84?= =?UTF-8?q?=E2=80=9C=E4=BD=BF=E7=94=A8=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md" "b/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md" index fc669f19b1d..3688a0e612e 100644 --- "a/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md" +++ "b/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md" @@ -98,7 +98,7 @@ System.out.println(a);// 0.100000024 System.out.println(b);// 0.099999964 System.out.println(a == b);// false ``` -具有基本数学知识的我们很清楚的知道输出并不是我们想要的结果(**精度丢失**),我们如何解决这个问题呢?一种很常用的方法是:**使用使用 BigDecimal 来定义浮点数的值,再进行浮点数的运算操作。** +具有基本数学知识的我们很清楚的知道输出并不是我们想要的结果(**精度丢失**),我们如何解决这个问题呢?一种很常用的方法是:**使用 BigDecimal 来定义浮点数的值,再进行浮点数的运算操作。** ```java BigDecimal a = new BigDecimal("1.0"); From 8a2e8728831f6e9cc86d9e401e067f6cf2869c72 Mon Sep 17 00:00:00 2001 From: lith0806 Date: Wed, 12 May 2021 08:46:50 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E5=8C=85=E8=A3=85=E7=B1=BB=E5=92=8C?= =?UTF-8?q?=E5=B8=B8=E9=87=8F=E6=B1=A0=E9=83=A8=E5=88=86=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Java\345\237\272\347\241\200\347\237\245\350\257\206.md" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" index 3202b4db1a8..f526cd0deb1 100644 --- "a/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" +++ "b/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" @@ -668,7 +668,7 @@ Integer i2 = new Integer(40); System.out.println(i1==i2); ``` -`Integer i1=40` 这一行代码会发生拆箱,也就是说这行代码等价于 `Integer i1=Integer.valueOf(40)` 。因此,`i1` 直接使用的是常量池中的对象。而`Integer i1 = new Integer(40)` 会直接创建新的对象。 +`Integer i1=40` 这一行代码会发生装箱,也就是说这行代码等价于 `Integer i1=Integer.valueOf(40)` 。因此,`i1` 直接使用的是常量池中的对象。而`Integer i1 = new Integer(40)` 会直接创建新的对象。 因此,答案是 `false` 。你答对了吗? From fdcf1671b9e946e4e5f1186e996f472496b7ed52 Mon Sep 17 00:00:00 2001 From: Joe Date: Wed, 12 May 2021 15:37:43 +0800 Subject: [PATCH 3/4] =?UTF-8?q?Update=20=E4=B8=87=E5=AD=97=E8=AF=A6?= =?UTF-8?q?=E8=A7=A3ThreadLocal=E5=85=B3=E9=94=AE=E5=AD=97.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...cal\345\205\263\351\224\256\345\255\227.md" | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git "a/docs/java/multi-thread/\344\270\207\345\255\227\350\257\246\350\247\243ThreadLocal\345\205\263\351\224\256\345\255\227.md" "b/docs/java/multi-thread/\344\270\207\345\255\227\350\257\246\350\247\243ThreadLocal\345\205\263\351\224\256\345\255\227.md" index f83d700c751..3650ddbb25e 100644 --- "a/docs/java/multi-thread/\344\270\207\345\255\227\350\257\246\350\247\243ThreadLocal\345\205\263\351\224\256\345\255\227.md" +++ "b/docs/java/multi-thread/\344\270\207\345\255\227\350\257\246\350\247\243ThreadLocal\345\205\263\351\224\256\345\255\227.md" @@ -186,7 +186,7 @@ public void set(T value) { } void createMap(Thread t, T firstValue) { - t.threadLocals = new `ThreadLocalMap`(this, firstValue); + t.threadLocals = new ThreadLocalMap(this, firstValue); } ``` @@ -338,7 +338,7 @@ private void set(ThreadLocal key, Object value) { for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { - `ThreadLocal` k = e.get(); + ThreadLocal k = e.get(); if (k == key) { e.value = value; @@ -420,7 +420,7 @@ private void replaceStaleEntry(ThreadLocal key, Object value, (e = tab[i]) != null; i = nextIndex(i, len)) { - `ThreadLocal` k = e.get(); + ThreadLocal k = e.get(); if (k == key) { e.value = value; @@ -551,7 +551,7 @@ private int expungeStaleEntry(int staleSlot) { for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { - `ThreadLocal` k = e.get(); + ThreadLocal k = e.get(); if (k == null) { e.value = null; tab[i] = null; @@ -602,7 +602,7 @@ if (h != i) { ### `ThreadLocalMap`扩容机制 -在``ThreadLocalMap.set()`方法的最后,如果执行完启发式清理工作后,未清理到任何数据,且当前散列数组中`Entry`的数量已经达到了列表的扩容阈值`(len*2/3)`,就开始执行`rehash()`逻辑: +在`ThreadLocalMap.set()`方法的最后,如果执行完启发式清理工作后,未清理到任何数据,且当前散列数组中`Entry`的数量已经达到了列表的扩容阈值`(len*2/3)`,就开始执行`rehash()`逻辑: ```java if (!cleanSomeSlots(i, sz) && sz >= threshold) @@ -653,7 +653,7 @@ private void resize() { for (int j = 0; j < oldLen; ++j) { Entry e = oldTab[j]; if (e != null) { - `ThreadLocal` k = e.get(); + ThreadLocal k = e.get(); if (k == null) { e.value = null; } else { @@ -711,7 +711,7 @@ private Entry getEntryAfterMiss(ThreadLocal key, int i, Entry e) { int len = tab.length; while (e != null) { - `ThreadLocal` k = e.get(); + ThreadLocal k = e.get(); if (k == key) return e; if (k == null) @@ -773,7 +773,7 @@ public class InheritableThreadLocalDemo { new Thread(new Runnable() { @Override public void run() { - System.out.println("子线程获取父类`ThreadLocal`数据:" + `ThreadLocal`.get()); + System.out.println("子线程获取父类ThreadLocal数据:" + ThreadLocal.get()); System.out.println("子线程获取父类inheritableThreadLocal数据:" + inheritableThreadLocal.get()); } }).start(); @@ -784,7 +784,7 @@ public class InheritableThreadLocalDemo { 打印结果: ```java -子线程获取父类`ThreadLocal`数据:null +子线程获取父类ThreadLocal数据:null 子线程获取父类inheritableThreadLocal数据:父类数据:inheritableThreadLocal ``` From 496f4cb8a364c099004b2ad2a48db14a42cb4b0d Mon Sep 17 00:00:00 2001 From: guide Date: Thu, 13 May 2021 10:19:35 +0800 Subject: [PATCH 4/4] =?UTF-8?q?Update=20MySQL=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E7=B4=A2=E5=BC=95.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...56\345\272\223\347\264\242\345\274\225.md" | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git "a/docs/database/MySQL\346\225\260\346\215\256\345\272\223\347\264\242\345\274\225.md" "b/docs/database/MySQL\346\225\260\346\215\256\345\272\223\347\264\242\345\274\225.md" index 4e8af540b5b..31ed9a66c24 100644 --- "a/docs/database/MySQL\346\225\260\346\215\256\345\272\223\347\264\242\345\274\225.md" +++ "b/docs/database/MySQL\346\225\260\346\215\256\345\272\223\347\264\242\345\274\225.md" @@ -22,20 +22,37 @@ ## 索引的底层数据结构 -### Hash & B+树 +### Hash表 & B+树 -Hash 索引指的就是 Hash 表,最大的优点就是能够在很短的时间内,根据 Hash 函数定位到数据所在的位置,也就是说 Hash 索引检索指定数据的时间复杂度可以接近 0(1)。 +哈希表是键值对的集合,通过键(key)即可快速取出对应的值(value),因此哈希表可以快速检索数据(接近 O(1))。 -但是,MySQL 并没有使用 Hash 索引而是使用 B+树作为索引的数据结构。**为什么呢?** +**为何能够通过 key 快速取出 value呢?** 原因在于 **哈希算法**(也叫散列算法)。通过哈希算法,我们可以快速找到 value 对应的 index,找到了 index 也就找到了对应的 value。 -**1.Hash 冲突问题** :知道 HashMap 或 HashTable 的同学,相信都知道它们最大的缺点就是 Hash 冲突了。不过对于数据库来说这还不算最大的缺点。 +```java +hash = hashfunc(key) +index = hash % array_size +``` + + + +![](https://img-blog.csdnimg.cn/20210513092328171.png) + +但是!哈希算法有个 **Hash 冲突** 问题,也就是说多个不同的 key 最后得到的 index 相同。通常情况下,我们常用的解决办法是 **链地址法**。链地址法就是将哈希冲突数据存放在链表中。就比如 JDK1.8 之前 `HashMap` 就是通过链地址法来解决哈希冲突的。不过,JDK1.8 以后`HashMap`为了减少链表过长的时候搜索时间过长引入了红黑树。 + +![](https://img-blog.csdnimg.cn/20210513092224836.png) + +为了减少 Hash 冲突的发生,一个好的哈希函数应该“均匀地”将数据分布在整个可能的哈希值集合中。 + +既然哈希表这么快,**为什么MySQL 没有使用其作为索引的数据结构呢?** + +**1.Hash 冲突问题** :我们上面也提到过Hash 冲突了,不过对于数据库来说这还不算最大的缺点。 **2.Hash 索引不支持顺序和范围查询(Hash 索引不支持顺序和范围查询是它最大的缺点:** 假如我们要对表中的数据进行排序或者进行范围查询,那 Hash 索引可就不行了。 试想一种情况: ```java -SELECT * FROM tb1 WHERE id < 500; +SELECT * FROM tb1 WHERE id < 500;Copy to clipboardErrorCopied ``` 在这种范围查询中,优势非常大,直接遍历比 500 小的叶子节点就够了。而 Hash 索引是根据 hash 算法来定位的,难不成还要把 1 - 499 的数据,每个都进行一次 hash 计算来定位吗?这就是 Hash 最大的缺点了。