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 最大的缺点了。 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` 。你答对了吗? 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"); 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 ```