在网上搜资料时候然后发现网上都说1.7版本的HashMap会发生死链也就是死循环,但是在HashMap中也会产生死循环,接下来直接看代码吧
代码
类名字我忘记改了这是我以前看park时候弄的但是这不重要
当你运行
代码语言:javascript复制public class parkAndUnpark {
static Map<String,String> map = new HashMap<>();
static class MyTask implements Runnable{
int start = 0;
public MyTask(int start){
this.start = start;
}
@Override
public void run() {
for(int i = start ; i<10000000;i =2){
map.put(Integer.toString(i),Integer.toBinaryString(i));
System.out.println(i);
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new MyTask(0));
Thread t2 = new Thread(new MyTask(1));
t1.start();
t2.start();
//主线程等待两个线程执行完
t1.join();
t2.join();
System.out.println(map.size());
}
}
好了这里会阻塞住 但是可能你没阻塞住所以多运行几次
实验jps查看运行线程
jstack
使用jstack分析堆栈快照
两个线程都在运行但是没有输出同时也没有结束这就产生了死循环,所以分析
分析
分析balanceInsertion 方法,上面就可以看到
代码语言:javascript复制 static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
TreeNode<K,V> x) {
//新插入的节点标为红色
x.red = true;
//无限for循环,定义xp、xpp、xppl、xppr变量,在循环体进行赋值,p就是parents
//- root:当前根节点
//- x :新插入的节点
//- xp :新插入节点的父节点
//- xpp :新插入节点的祖父节点
//- xppl:新插入节点的左叔叔节点
//- xppr:新插入节点的右叔叔节点
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;
}
//省略其他代码
}
总的来说上边的源码就是,新插入一个节点,该方法要保持红黑树的五个性质
性质1. 节点是红色或黑色。 性质2. 根节点是黑色。 性质3 每个叶节点(NIL节点,空节点)是黑色的。 性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点) 性质5. 从任一节点到其每个叶子的路径上包含的黑色节点数量都相同。