HashMap
特点
(1)HashMap是线程不安全的,意味着多线程下不能使用该方法,可能会导致意想不到的结果。如果我们细细的查看源码,就会发现HashMap方法没有synchronized这样的加锁操作。
(2)初始化容量:HashMap的默认容量是16.把1像左移动4个字节,变成了10000,是2的4次方也就是16。put后才开辟空间。
(3)默认加载因子:0.75f。
(4)底层实现:数组、链表、红黑树。
Java中的哈希表采用链地址法,当桶中的存储元素(链表)大于8的时候,进行一次判断。当数组的长度大于64的时候,自动转换成红黑树。转化成红黑树的两个必要条件:桶节点的数量大于8、整个数组的长度大于64。
(5)如何扩容:每一次扩容大小是当前容量的2倍。当map键值对数大于等于加载因子*数组长度时,可能发生扩容;或者当某个桶的链表长度大于8,但是数组长度小于64的时候。
(6)允许键值对中键的值为null。
Hashtable
特点
(1)Hashtable的方法中,均只是简单加了synchronized关键字,在多线程下,是线程安全的。
(2)初始化容量:初始化容量为11。
(3)底层实现:数组和链表。
(4)如何扩容:newsize = olesize * 2+1。拷贝过程中需要该线程完成整个扩容过程,涉及大量的元素拷贝,效率比较低。
(5)Hashtable方法,直接使用了一把大锁,如果多个线程访问同一个Hashtable就很容易产生冲突。
(6)不允许键值对中键的值为null。
ConcurrentHashMap
特点
(1)ConcurrentHashMap方法中,针对性加锁,线程安全。
对于读的操作,没有加锁,而是使用了volatile关键字保证了内存可见性。只对于写的操作加锁,加锁使用synchronized关键字。细化了锁的粒度。锁的时候不是直接锁住整个对象,而是每一个哈希桶,降低了锁的冲突概率。
(2)ConcurrentHashMap更加充分的使用CAS特性,避免了出现重量级锁的情况。
(3)针对扩容的方式进行优化,采用化零为整的策略。使用锁分段技术,把若干个哈希桶分成一个 "段" ,对每个段分别加锁。降低锁竞争的概率。
(4)不允许键值对中键的值为null。
三者区别
(1)HashMap线程不安全,其他的线程安全。
(2)Hashtable使用一把大锁,导致锁冲突概率很高,ConcurrentHashMap的每一个哈希桶使用一把锁,锁冲突的概率小。
(3)ConcurrentHashMap相对于Hashtable使用了其他优化策略,比如使用CAS特性、使用锁分段技术等。
(4)HashMap中,key值允许为null,另外两个不允许。