关于HashMap的一点儿学习

关于HashMap底层原理

首先了解到 HashMap 是用来存贮一个个 <key,value>(<键,值>)的集合,实则 HashMap 则为一个数组,而这种 <key,value> 对则为存在数组中某一位置的值;

1、那么每个 <key,value> 对是存于什么位置呢?原来在将每个 <key,value> 存入前,还利用一个哈希函数来计算位置 index = Hash(key); 然后按照所得位置在数组存入 <key,value> 对。那么插入过多的 <key,value> 对时,则必然会出现 index冲突 的情况,这时就需要数据结构中的 拉链法 来处理冲突问题,既每当出现index冲突问题时,将新 <key,value> 对插入对应位置,此位置上的原 <key,value> 弹出,新 <key,value> 对通过指针指向原 <key,value> 对,从而达到链表的效果并同时解决了插入index冲突问题。

2、那么当取value时用的GET(key)方法如何获取value的呢?当使用Get(key)方法取值时,会通过所填key计算 index = Hash(key),然后在对应位置上的链表进行检索符合键值为所填key的<key,value>对并返回value的值。

注:

1、HashMap 默认长度16,并且每次扩展或手动初始化时长度必须为2的幂;
2、index = HashCode(Key) & (Length - 1) (&为二进制位运算);
3、默认长度为16的好处,则是使插入的<key,value>对分布均匀。

关于HashMap的死锁

hashmap是单线程安全的,挡在并发多线程情况下,易出现死锁情况,原因:
首先hashmap既是一个table[];当hash(key)超出原有范围时,便会扩容出发rehash
;在单线程情况下,此操作是安全的,并且若原hash表中链表为A->B->C;那么转入新表中时,可能为C->B->A,既顺序会变反;
在rehash时会出发的一个关键方法(transfer),见源码:

void transfer(Entry[] newTable, boolean rehash) {
         int newCapacity = newTable.length;
         for (Entry<K,V> e : table) {
             while(null != e) {
                Entry<K,V> next = e.next;
                 if (rehash) {
                     e.hash = null == e.key ? 0 : hash(e.key);
                 }
                 int i = indexFor(e.hash, newCapacity);
                 e.next = newTable[i];
                 newTable[i] = e;
                 e = next;
             }
         }

分析:e节点为当前遍历链表的第一个节点,用next保存e.next;接着,e.next指向newtable[i]的第一个节点;将e插入newtable[i]的链表的头部,接着e = next并继续循环;如此,就将当前链表转移进了新的hashmap,且容易明白为什么插入新表后顺序会相反;

那么死锁问题就出现在了这里,当多线程访问时,假设当前有两个线程同时插入数据,并都需要进行rehash,则当第一个线程rehash时并进行到next = e.next时,线程调度到线程2,则线程1暂时挂起;当线程2完成rehash建成新hashmap2时,此时,e与next皆指向的是新hashmap2中的节点,且next.next = e;则线程一继续执行,此时当执行完第一个转移时,e = next ; next = e.next ;既原有e 与 next 相互将换并继续执行循环,不难看出此时已出现环状链表;故此新建hash表进行get()时,则会出现死锁的状况;

解决:使用ConCurrentHashMap

有序的Map类

TreeMap和LinkedHashmap都是有序的。(TreeMap默认是key升序,LinkedHashmap默认是数据插入顺序)
TreeMap是基于比较器Comparator来实现有序的。
LinkedHashmap是基于链表来实现数据插入有序的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值