当前位置:   article > 正文

JDK1.8的HashMap死循环复现_1.8的hashmap会出现死链吗

1.8的hashmap会出现死链吗

文章目录


前言

下面聊聊JDK1.7HashMap的死循环问题,在这之前首先要知道JDK1.7的HashMap底层是数组 + 链表的形式的


正文

JDK1.8解决了JDK1.7的头插法导致死循环的问题,但是JDK1.8同样会死循环,下面我们用两个线程进行演示

abstract class Test {
    public static void main(String[] args) throws InterruptedException {
        Map<String,Integer> map = new HashMap<>();
        Thread t1 = new Thread(() -> {
            //添加奇数
            for (int i = 1; i < 2000000; i += 2) {
                map.put(Integer.toString(i), i);
                System.out.println(Thread.currentThread() + ":" + i);
            }
        });
        Thread t2 = new Thread(()->{
            //添加偶数
            for(int i = 0 ; i<2000000;i+=2){
                map.put(Integer.toString(i),i);
                System.out.println(Thread.currentThread() + ":" + i);
            }
        });
        t1.start();
        t2.start();
        //主线程等待t1和t2执行完成
        t1.join();
        t2.join();
        System.out.println(map.size());
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在这里插入图片描述
我们使用jps和jstack来进行分析
在这里插入图片描述

D:\javaCode\LeedCode>jstack 63556
2023-01-23 02:57:16
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.281-b09 mixed mode):

"Thread-1" #13 prio=5 os_prio=0 tid=0x0000023ef0e98800 nid=0xe648 runnable [0x00000073318ff000]
   java.lang.Thread.State: RUNNABLE
        at java.util.HashMap$TreeNode.treeify(HashMap.java:1948)
        at java.util.HashMap$TreeNode.split(HashMap.java:2180)
        at java.util.HashMap.resize(HashMap.java:714)
        at java.util.HashMap.putVal(HashMap.java:663)
        at java.util.HashMap.put(HashMap.java:612)
        at com.jianglianghao.mianshi_test.Test.lambda$main$1(Test.java:26)
        at com.jianglianghao.mianshi_test.Test$$Lambda$2/2093631819.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

"Thread-0" #12 prio=5 os_prio=0 tid=0x0000023ef0e98000 nid=0xf2cc runnable [0x00000073317ff000]
   java.lang.Thread.State: RUNNABLE
        at java.util.HashMap$TreeNode.treeify(HashMap.java:1948)
        at java.util.HashMap$TreeNode.split(HashMap.java:2180)
        at java.util.HashMap.resize(HashMap.java:714)
        at java.util.HashMap.putVal(HashMap.java:663)
        at java.util.HashMap.put(HashMap.java:612)
        at com.jianglianghao.mianshi_test.Test.lambda$main$0(Test.java:19)
        at com.jianglianghao.mianshi_test.Test$$Lambda$1/558638686.run(Unknown Source)
        at java.lang.Thread.run(Thread.java:748)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

追溯到代码层面发现是在树化的时候导致的死循环,后续也测了几次,发现死循环的几次的代码不同,下面这一次的死循环出现在putTrereVal,也就是添加树节点这里,而第二个线程卡在了balanceInsertion

D:\javaCode\LeedCode>jstack 64008
2023-01-23 02:40:20
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.281-b09 mixed mode):

"Thread-1" #13 prio=5 os_prio=0 tid=0x000002d51df7a000 nid=0xf834 runnable [0x000000dba0dfe000]
   java.lang.Thread.State: RUNNABLE
        at java.util.HashMap$TreeNode.root(HashMap.java:1824)
        at java.util.HashMap$TreeNode.putTreeVal(HashMap.java:1978)
        at java.util.HashMap.putVal(HashMap.java:638)
        at java.util.HashMap.put(HashMap.java:612)
        at com.jianglianghao.mianshi_test.Test$MyTask.run(Test.java:23)
        at java.lang.Thread.run(Thread.java:748)

"Thread-0" #12 prio=5 os_prio=0 tid=0x000002d51df71000 nid=0xe5a0 runnable [0x000000dba0cfe000]
   java.lang.Thread.State: RUNNABLE
        at java.util.HashMap$TreeNode.balanceInsertion(HashMap.java:2239)
        at java.util.HashMap$TreeNode.treeify(HashMap.java:1945)
        at java.util.HashMap$TreeNode.split(HashMap.java:2180)
        at java.util.HashMap.resize(HashMap.java:714)
        at java.util.HashMap.putVal(HashMap.java:663)
        at java.util.HashMap.put(HashMap.java:612)
        at com.jianglianghao.mianshi_test.Test$MyTask.run(Test.java:23)
        at java.lang.Thread.run(Thread.java:748)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
final TreeNode<K,V> root() {
    for (TreeNode<K,V> r = this, p;;) {
        if ((p = r.parent) == null)
            return r;
        r = p;
    }
}


static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
                                                    TreeNode<K,V> x) {
            x.red = true;
            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
                if ((xp = x.parent) == null) {
                    x.red = false;
                    return x;
                }
                else if (!xp.red || (xpp = xp.parent) == null)
                    return root;
                if (xp == (xppl = xpp.left)) {
                    if ((xppr = xpp.right) != null && xppr.red) {
                        xppr.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }
                    else {
                        if (x == xp.right) {
                            root = rotateLeft(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateRight(root, xpp);
                            }
                        }
                    }
                }
                else {
                    if (xppl != null && xppl.red) {
                        xppl.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    }
                    else {
                        if (x == xp.left) {
                            root = rotateRight(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateLeft(root, xpp);
                            }
                        }
                    }
                }
            }
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63

其实从root方法中也能看出来了肯定是在putVal添加节点或者树化的时候导致父子节点之间互连然后导致的死循环,但是什么原因还是不得而知。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/576462
推荐阅读
相关标签
  

闽ICP备14008679号