HashMap
JDK1.7:数组+链表
JDK1.8之后:数组+链表+二叉树
Hashmap数据结构是由数组(table)+链表(entry)组成,每个entry对应着一个table的索引页对应着一个唯一的hash地址值
我们看到Hashmap在使用空参构造的时候会默认加载一个长度为16,加载因子为0.75的集合
HashMap的put方法(保证key的唯一性)
Hashmap在put的数据的时候,在底层代码中会先通过判断put的值的key是否为null,如果为null,会固定存放到table[0]下面,如果不为null,会通过hash()方法计算出key对应的hash地址,通过hash地址去寻找数据应存放的table的指定索引下,找到之后会判断put的key在链表中是否存在(地址值和具体值都要判断)如果存在则为替换,如果不存在则为新增接!
Hashtable是synchronized,因为它对remove,put,get进行了同步控制,保证了Hashtable的线程安全性,多个线程可以共享一个Hashtable因为任何线程要更新Hashtable时要首先获得同步锁,其它线程要等到同步锁被释放之后才能再次获得同步锁更新Hashtable。由于是线程安全的所以在单线程环境下它比HashMap要慢,如果只需要单一线程,使用HashMap性能要好过Hashtable。
HashMap和Hashtable的区别
Hashmap可以存储Key为null的值,线程不安全,但是效率低
Hashtable不可以存储Key为null的值,线程安全,但是效率高
在源代码里面我们可以清楚的看到,Hashtable的put方法中有这synchronize修饰,明显是线程安全的,而在Hashmap中并没有任何相关关键字修饰,而且没有加锁,所以线程是不安全的;
Java 5提供了ConcurrentHashMap,它是HashTable的替代使用了锁分段技术,因为ConcurrentHashMap将Map分段了,每个段进行加锁而不是像Hashtable,SynchronizedMap是整个map加锁,这样就可以多线程访问了,ConcurrentHashMap默认运行16个线程同时访问该map。但是可以通过一个函数来设置增加或减少最大可运行访问的线程数目。
ConcurrentHashMap和Hashtable的区别
ConcurrentHashMap与HashTable都可以用于多线程的环境,但是当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的时间。因为ConcurrentHashMap引入了分割(segmentation),不论它变得多么大,仅仅需要锁定map的某个部分,而其它的线程不需要等到迭代完成才能访问map。简而言之,在迭代的过程中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。