提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
一、HashMap
hashmap是一种存储和检索键值对的数据结构,键具有唯一性,根据键计算得到的哈希值决定存放的位置,如果此位置为空,则直接将节点插入;如果不为空,则遍历链表看有没有相同的键值,如果有,则将当前值替换掉旧值,如果没有,则放在链表的最末端。
底层结构
数组加链表,链表是采用拉链法解决hash冲突的方式,当这个链表长度超过8以后,链表会转化为红黑树,以提高查询效率。
扩容机制
初始容量为16
当元素数量超过容量乘负载因子(0.75)时,就会将容量扩大至原来的两倍。
扩容后,会将所含元素重新hash一遍放入正确的位置,比较耗时。
二、LinkedHashMap
与HashMap的底层结构相比,加了一个双向链表用来维护HashMap的插入顺序。当我们需要按照插入顺序获取元素时,就使用linkedhashmap。
三、TreeMap
底层结构为红黑树,可以按照存入元素的key值对元素进行排序存储,默认按升序存储。
四、为什么重写equals方法需要重写hash方法
不重写的时候,equals方法是用来比较对象地址值是否相等。
重写是为了让equals可以比较对象具体的值是否相等。
默认的hashcode是计算对象内存地址的hash值。
如果只写了equals方法,就会出现两个对象equals结果相等,但hashcode值不相等的情况,在类似于hashmap这样的散列结构中就会出现问题。
因为hashmap使用hashcode来计算对象的位置,如果存储两个完全相同的对象,但有着不同的hashcode值就会导致两个对象就会存储在不一样的位置,违背了hashcode键值的唯一性。
五、linkedhashmap和treemap有什么不同
1、linkedhashmap底层结构是在hashmap的接触上加上一个双向链表,用来维护元素插入的顺序,可以按照插入顺序进行遍历;treemap底层是一个红黑树,按照键值对元素进行排序。
2、linkedhashmap在查找、新增、修改等方面的性能比较好;而hashmap在根据key值进行范围查询有比较好的性能。
六、hashtable和hashmap的区别
1、hashtable是线程安全的,hashmap是线程不安全的。
2、hashmap可以有一个空键值、多个空值;但hashtable不允许插入空键或控制。
3、单线程下更推荐hashmap,因为hashtable有锁的开销。
七、ConcurrentHashMap
推荐使用ConcurrentHashMap保证线程安全。
为什么ConcurrentHashMap的键和值都不能为空
因为多线程并发环境下无法保证get(key)得到null的结果是设置的还是key值没有对应的映射,因为hashmap单线程下可以通过containskey来判断,但ConcurrentHashMap在使用containskey的同时,可能值已经被其他线程改变了。
jdk1.7实现方式
通过分段锁实现线程安全的,将数组分成多段 segement,通过继承ReentrantLock对每个segment进行上锁。这样当多线程同时想要修改同一个segment中的数据时,只允许一个线程进行修改。(对写加锁)但是 ConcurrentHashMap 不支持将冲突的链表转换为红黑树,因为在多线程并发修改链表时,会导致死锁和数据不一致等问题。
jdk1.8实现方式
底层结构和hashmap一样变成了数组加链表/红黑树的结构,但取消了分段锁,而是使用了更细粒度的锁。采用CAS+Sychronized实现了桶级别的锁,只需要锁住每个链表的首节点或是红黑树的根节点就行,这样多线程只有在同时访问一个桶时才会出现冲突。
在添加元素的时候会判断容器是否为空,如果为空,则会用CAS和volatile初始化;
如果不为空,根据存储的元素计算该位置是否为空,如果该位置为空,就会用CAS来设计该节点,;否则使用sychronized加锁去实现,去遍历桶中的元素,替换或新增节点到桶中。