Hashtable 从jdk1.0就有了,而HashMap是jdk1.2添加了,ConcurrentHashMap在jdk1.5才提供。Hashtable和ConcurrentHashMap都是线程安全的。但是ConcurrentHashMap是1.5添加的更高级的并发工具。它使用了分段锁技术来实现更细粒度的同步。因此ConcurrentHashMap比Hashtable效率较高,因此在多线程情况下一般使用ConcurrentHashMap。而HashMap是非线程安全的,因此一般在单线程下使用。
优先选择:多线程访问:ConcurrentHashMap。单线程访问:HashMap
验证写个简单易懂的代码作为例子,代码如下,然后分别在有注释的两行代码前设置断点:
public class HashMapL {public static void main(String[] args) {HashMap<Integer, Integer> hashMap = new HashMap<>();hashMap.put(null, null); //test null key and null value;for(int i=0; i<16; i++){hashMap.put(i, i); //autoboxing}}
以debug模式运行上面代码可以看出HashMap
从上图可以看到,负载因子loadfactor默认值是0.75。注意,threshold现在的值时0。根据HashMap源码里面的注释可以知道,这个值是在给table分配空间后才会计算threshold的值,分配前它的值是0,而现在table的值为null,尚未分配。那么这里的table是什么呢?了解拉链式哈希表的人就会轻易知道它是一个链表数组。
按F6执行下一步,给hashMap赋值,并且是空值,来验证与Hashtable的区别:可以保存空值。
从上图可以看到,
继续按F6,直到size=threshold=12,此刻table的id和之前的一样,还是id=24
现在再按一次F6执行下一步,向hashMap里添加一个元素,让元素的总数size大于阈值threshold
从图片中看到,table的id=104,大小为32,阈值threshold=24。而之前的id=24,大小为16,threshold=12。因此得出结论,
当元素大小size大于阈值threshold时就会进行再哈希。再哈希后,HashMap就会自动扩容为之前的2倍。并且用一个新的对象代替原来的对象。由此也可得知,自动扩容是需要消耗资源的,要尽量减少自动扩容的发生。
参考:API文档How HashMap works in java,强烈推荐!(之前看了这篇文章感觉真的太好了,有种自己不用写了感觉。所以这篇博文最主要的目的是总结下HashMap的特点。和这篇文章的debug思路)
新闻热点
疑难解答