码迷,mamicode.com
首页 > 其他好文 > 详细

HashMap、HashTable、SycronizedMap、ConcurrentHashMap、ConcurrentSkipListMap简单总结

时间:2019-12-25 11:36:09      阅读:122      评论:0      收藏:0      [点我收藏+]

标签:异常   机制   行操作   list   扩容   冲突   code   内存数据   效率   

1、默认容量?

HashTable默认容量为11,计算hash的方式为如下:

int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;

根据证明,对素数或奇数直接取模,分布的会更均匀。
其它Map的默认容量都为16,HashMap计算Hash的方式如下:

static final int hash(Object key) {
   int h;
   return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

static int indexFor(int h, int length) {
   return h & (length-1);
}

 

concurrentHashMap计算Hash的方式如下:

static final int spread(int h) {
   return (h ^ (h >>> 16)) & HASH_BITS;
}

第一步计算hash采用了扰动的算法,防止不同hashCode的高位不同但低位相同导致的hash冲突。

第二步计算index采用了位运算。位运算(&)效率要比代替取模运算(%)高很多,主要原因是位运算直接对内存数据进行操作,不需要转成十进制,因此处理速度非常快。

那么,为什么可以使用位运算(&)来实现取模运算(%)呢?这实现的原理如下:

X % 2^n = X & (2^n - 1)

2^n表示2的n次方,也就是说,一个数对2^n取模 == 一个数和(2^n - 1)做按位与运算 。

假设n为3,则2^3 = 8,表示成2进制就是1000。2^3 -1 = 7 ,即0111。

此时X & (2^3 - 1) 就相当于取X的2进制的最后三位数。

从2进制角度来看,X / 8相当于 X >> 3,即把X右移3位,此时得到了X / 8的商,而被移掉的部分(后三位),则是X % 8,也就是余数。

 

2、扩容机制:默认扩容因子都是0.75,HashTable扩容为2*length+1,其它扩容为2*length。扩容机制、默认容量、hash计算是密切相关的。

3、实现方式:Hashtable 继承了 Dictionary类,而 HashMap 继承的是 AbstractMap 类。

4、迭代器不同:HashMap 中的 Iterator 迭代器是 fail-fast 的,而 Hashtable 的 Enumerator 不是 fail-fast 的。

5、Hashtable 是不允许键或值为 null 的,HashMap 的键值则都可以为 null。

因为Hashtable在我们put 空值的时候会直接抛空指针异常,但是HashMap却做了特殊处理。

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}



Hashtable使用的是安全失败机制(fail-safe),这种机制会使你此次读到的数据不一定是最新的数据。

如果你使用null值,就会使得其无法判断对应的key是不存在还是为空,因为你无法再调用一次contain(key)来对key是否存在进行判断,ConcurrentHashMap同理。

HashMap、HashTable、SycronizedMap、ConcurrentHashMap、ConcurrentSkipListMap简单总结

标签:异常   机制   行操作   list   扩容   冲突   code   内存数据   效率   

原文地址:https://www.cnblogs.com/minikobe/p/12095704.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!