hashmap:
HashMap就是数组+链表(哈希表或者散列函数)+红黑树的组合实现,每个数组元素存储一个链表的头结点,本质上来说是哈希表“拉链法”的实现。
主干是数组,entry的value是链表,链表>8个后转红黑树。普通时间复杂度就是hash, 一般时间复杂度O(logn)
主要有put和get方法,put的原理是,通过hash&length-1计算index,此时记作Entry[index]=该元素。如果index相同就是新入的元素放置到Entry[index],原先的元素记作Entry[index].next
get就比较简单了,先遍历数组,再遍历链表元素。
null key总是放在Entry数组的第一个元素(允许存放一个空键值对的原因)
解决hash冲突的方法:链地址法(将所有关键字为同义词的记录存储在一个单链表中,我们称这种表为同义词子表,在散列表中只存储所有同义词子表的头指针。)
再散列rehash的过程:确定容量超过目前哈希表的容量,重新调整table 的容量大小,当超过容量的最大值时
HashMap的容量size乘以负载因子[默认0.75] = threshold 将会触发扩容。
-
REEIFY_THRESHOLD
用于判断是否需要将链表转换为红黑树的阈值。 -
HashEntry 修改为 Node。
两种遍历方式:EntrySet和key-value
强烈建议
使用第一种 EntrySet 进行遍历。
第一种可以把 key value 同时取出,第二种还得需要通过 key 取一次 value,效率较低。
JDK 没有对hashmap做任何的同步操作,所以并发会出问题,甚至出现死循环导致系统不可用。这就引入了concurrenthashmap
concurrenthashmap:
ConcurrentHashMap 的 get 方法是非常高效的,因为整个过程都不需要加锁。
push方法抛弃了原有的 Segment 分段锁,而采用了 CAS + synchronized
来保证并发安全性。
hashtable:
整表锁,效率低下