2022-09-27 10:58阅读: 11评论: 0推荐: 0

【链表】关于链表结构

关于链表结构

每次看链表结构相关代码就有点晕,还看不明白,得想半天。看下面这篇分析的时候又感觉有点费劲了。
面试官: HashMap 为什么线程不安全?

这个问题以前了解过,时间一长就忘记了。先说结论:

JDK 1.7 HashMap 上的链表结构使用的头插法,并发情况会导致生成环形链表。这样 HashMap 轮循时会在环形链表上陷入死循环。

JDK 1.7 中 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;
}
}
}

未 resize 前的数据结构:

  1. 最开始 hash 表 size=2,key=3,7,5,则都在 table[1] 中。
  2. 然后进行 resize,使 size 变成 4。

table 遍历的是 3,7,5 链表

get, set 方法看习惯了,直接获取、设置 next 属性看着还挺别扭。好像是因为这个原因,理解起来有点障碍了。

Entry<K,V> next = e.next; 改写成 e.getNext()

e.next = newTable[i]; 改写成 e.setNext(newTable[i]);

理解起来就不一样了。

线程A挂起前:

  • next 已经先赋值为 7,5 链表。
  • newTable[i] 还没有元素,此时 e = 3,所以,e.next = newTable[i] ,即 3 指向了 null

先记住下面的描述方便理解:

  • e.nextnext 容易混淆,注意区分,两者是不同的变量。
  • 后续newTable[i] 指向的是链表头部,取值也直接取的头部。不涉及遍历的话不用关心链表其它位置的元素。
  • 链表 next 后,以 next 元素为头部,取其后的元素为组成的链表。不再包含前面的元素。关联单向链表对象来思考,对象只有 next 属性,没有 pre 属性。所以,会丢失前面的节点信息。

本文作者:JamKing

本文链接:https://www.cnblogs.com/JamKing/p/16733826.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   JamKing  阅读(11)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.