深入浅出hashMap与hashTable

比较一下hashMap与hashTable。

hashMap与hashTable 同样都是 数组+链表的形式去存储数据

以HashMap为例 默认数组长度为16,每一个数组地下都挂着一个链表

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

这个时候比如为1的元素下挂着一个链表

a
b
c
 
 
 

可以理解为16个数组元素下每一个都挂着不计长度的链表

当我的数据来得时候,每一个数组元素都可以存放着不同的key值,而且可以存放多个(这个计算的过程我们称之为哈希碰撞)。 链表里存放着不同的key值。

值得一提的是, 当每次put的元素在1-16元素范围内的比例超过0.75(装载因子)的时候 进行翻倍扩容 ,数组的长度会从16变成32,32变64.

当数组长度已经变成64并且链表长度达到8以后进行树化

什么是树化 即 链表变成以红黑树的方式去存储,

红黑树的好处又是什么,

红黑树在存储的时候会按照适配的比例去挂载分支数据,也就是说不会出现一个分支一直挂数据 另一个分支无数据的情况,

这个时候去找数据 就会比链表里找数据要缩短时间。


hashTable是线程安全的,而hashTable不是。为什么这样说,对源码有兴趣的同学可以打开你的项目找到如下这段代码

 1 public synchronized V get(Object key) {
 2         Entry<?,?> tab[] = table;
 3         int hash = key.hashCode();
 4         int index = (hash & 0x7FFFFFFF) % tab.length;
 5         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
 6             if ((e.hash == hash) && e.key.equals(key)) {
 7                 return (V)e.value;
 8             }
 9         }
10         return null;
11     }
View Code

可以看到这个关键字:synchronized 。 这个关键字是用来干嘛的,对没错就是  线程同步

什么叫线程同步,我的理解是 当我的数据同时访问的时候,a和b 同时用哈希算法算到了同一个位置  那么 b就需要排队。等a存储完成以后 b再去存储。这就是线程安全。那么带来的问题就是 性能会很差。如果高并发的情况下,会让人抓狂。

其实HashMap使用得当 是非常安全的。 而且很好用。

提一点 jdk1.5以后 为了解决线程安全+效率问题  

CorruntHashMap 

应运而生。

这个map呢  你可以理解图中的 数据元素和链表都是上了锁的。  那么只有在哈希运算的时候,并且两个来源数据都计算到同一个位置的时候 才会触发,有序排队存储。


原文地址:https://www.cnblogs.com/wuhaojs/p/15342056.html