HashMap实现方法概述

HashMap的实现思路:

HashMap是采用数组( table[] ) + 链表存储的,table数组的每个元素都是一个链表。 链表的核心数据结构是Node:

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
        ...
}

即存储一个key-value键值对,外加hash值和其指向的节点的地址引用。

当put(key,value)时,过程如下:

  1. 根据key值计算一个hash值,然后根据hash值和table的length计算该key所在的桶的索引(即table[i])
  2. 在table[i] 这个链表中依次查找key,如果能找到,就用新value替换掉之前的老value; 如果找不到,就在此链表中新增一个节点,用来存储这个key-value键值对;
  3. 新增节点时,new 一个node1并令其存储table[i],然后再new一个node2,令node2的next指向node1, 再令table[i] = node2,这样就把新增的node2插入到了之前的table[i]链表的第一个位置;
  4. 插入完成后,当前的hashmap中包含的key-value总数(size)增加了1,这时要检查是否超过了我们设定的阈值threshold,如果超过了,就要对hashmap进行扩容,并将数据从老的hashmap迁移到新的hashmap中去
  5. 扩容(resize)时,遍历老的table,在其中遍历每个table[i]链表,根据hash值和新容量对每个node计算其新的桶索引(newTable[i])。将node插入到新的桶的最前边去。

至此,put过程结束。

而在多线程的情况下,当执行到步骤5时,由于多个线程都要不断地将node插入到桶的最前面去,在这个过程中可能会形成环形链接。

参考文章:https://coolshell.cn/articles/9606.html 写的太好了,必须推荐。以上只是对文章中的思想进行了总结。

线程安全的Hashtable

hashtable是通过将put,get等方法加上synchronized关键字(同步锁),每次只能有一个线程进行存或取。以此避免发生线程不安全问题,但这种方式必然会以牺牲效率为代价。

线程安全的ConcurrentHashMap

ConcurrentHashMap的实现与Hashtable有所不同,它是通过在table之外再加一层segment

图片引用(http://www.yupoo.com/photos/goldendoc/81556254/

当每次进行put和get操作时,不必对整个map都加锁,只需要对table所在的segment加上同步锁就可以了。另外rehash也是在单个segment中进行,成本较低。这样既避免了线程安全问题,又保证了高并发的存取效率。

参考文章:https://liqianglv2005.iteye.com/blog/2025016

其他实现了map接口的类:

TreeMap:除了实现Map接口之外还实现了SortedMap接口,集合中的映射关系有一定的顺序(按照键升序、降序或自定义顺序),但性能较差,线程不安全。

LinkedHashMap:它是HashMap的子类,用双向链表存储,遍历顺序与插入时的顺序一样。它在resize时不用对key-value重新排序,但它是用链表维护内部顺序,增加了空间开销的同时,也因此遍历的性能较高。它也是线程不安全的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值