比较一下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 }
可以看到这个关键字:synchronized 。 这个关键字是用来干嘛的,对没错就是 线程同步
什么叫线程同步,我的理解是 当我的数据同时访问的时候,a和b 同时用哈希算法算到了同一个位置 那么 b就需要排队。等a存储完成以后 b再去存储。这就是线程安全。那么带来的问题就是 性能会很差。如果高并发的情况下,会让人抓狂。
其实HashMap使用得当 是非常安全的。 而且很好用。
提一点 jdk1.5以后 为了解决线程安全+效率问题
CorruntHashMap
应运而生。
这个map呢 你可以理解图中的 数据元素和链表都是上了锁的。 那么只有在哈希运算的时候,并且两个来源数据都计算到同一个位置的时候 才会触发,有序排队存储。