课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
在Java开发的语言世界里,有很多相似而功能不同的单词,开发工程师们务必要分清楚,本文沈阳达内IT培训为大家介绍HashMap和Hashtable的区别。
1、两者最主要的区别在于Hashtable是线程安全,而HashMap则非线程安全
Hashtable的实现方法里面都添加了synchronized关键字来确保线程同步,因此相对而言HashMap性能会高一些,平时使用时若无特殊需求建议使用HashMap,在多线程环境下若使用HashMap需要使用Collections.synchronizedMap()方法来获取一个线程安全的集合(Collections.synchronizedMap()实现原理是Collections定义了一个SynchronizedMap的内部类,这个类实现了Map接口,在调用方法时使用synchronized来保证线程同步,当然了实际上操作的还是我们传入的HashMap实例,简单的说Collections.synchronizedMap()方法在操作HashMap时自动添加了synchronized来实现线程同步,类似Collections.synchronizedXX方法也是此原理)
2、HashMap可以使用null作为key,而Hashtable则不允许null作为key
虽说HashMap支持null值作为key,不过建议还是尽量避免这样使用,因为一旦不小心使用了,若因此引发一些问题,排查起来很是费事
HashMap以null作为key时,总是存储在table数组的第一个节点上
HashMap是对Map接口的实现,HashTable实现了Map接口和Dictionary抽象类
HashMap的初始容量为16,Hashtable初始容量为11,两者的填充因子默认都是0.75
HashMap扩容时是当前容量翻倍即:capacity*2,Hashtable扩容时是容量翻倍+1即:capacity*2+1
3、两者计算hash的方法不同
Hashtable计算hash是直接使用key的hashcode值对数组的长度直接进行取模
int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length;
HashMap计算hash对key的hashcode值进行了二次hash,以获得更好的散列值,然后对数组长度取模,JDK8将key的hashcode高16位异或下来,然后对数组长度取模
HashMap和Hashtable的底层实现都是数组+链表结构实现,添加、删除、获取元素时都是先计算hash,根据hash和table.length计算index也就是table数组的下标,然后进行相应操作
4、Hashtable,HashMap,ConcurrentHashMap,HashSet底层实现原理与线程安全问题
1) Hashtable是线程安全的,它的方法是同步了的,可以直接用在多线程环境中
2) HashMap则不是线程安全的。在多线程环境中,需要手动实现同步机制
3) Hashtable中采用的锁机制是一次锁住整个hash表,从而同一时刻只能由一个线程对其进行操作;ConcurrentHashMap使用锁分段技术,一次锁住一个桶。ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素, 每个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。ConcurrentHashMap默认将hash表分为16个桶,诸如get,put,remove等常用操作只锁当前需要用到的桶。原来只能一个线程进入,现在却能同时有16个写线程执行,并发性能的提升是显而易见的(Spring容器Bean的初始化:为BeanFactory新建XmlBeanDefinitionReader,加载并从Root开始解析xml配置文件,并遍历各级的节点。根据类型的不同的处理,最后都会集中在处理bean类型的节点。将bean节点映射成BeanDefinitionHolder,并在BeanFactory中注册,key为bean的name,value为BeanDefinition对象。由BeanFactory的ConcurrentHashMap类型的成员变量持有)
4) 在迭代方面,ConcurrentHashMap当iterator被创建后集合再发生改变就不再是抛出ConcurrentModificationException,取而代之的是在改变时new新的数据从而不影响原有的数据。iterator完成后再将头指针替换为新的数据。这样iterator线程可以使用原来老的数据。而写线程也可以并发的完成改变