ConcurrentSkipListMap源码---JDK1.8

 private V doPut(K key, V value, boolean onlyIfAbsent) {
        Node<K,V> z;             // added node
        if (key == null)
            throw new NullPointerException();
        Comparator<? super K> cmp = comparator;
        outer: for (;;) {
            //找到key对应的前继节点b
            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
                //如果n不为null
                if (n != null) {
                    Object v; int c;
                    //获取n的next节点
                    Node<K,V> f = n.next;
                    //发生竞争,break
                    if (n != b.next)               // inconsistent read
                        break;
                    //如果n已经被删除
                    if ((v = n.value) == null) {   // n is deleted
                        n.helpDelete(b, f);
                        break;
                    }
                    //如果b已经被删除
                    if (b.value == null || v == n) // b is deleted
                        break;
                    //如果c>0,说明当前节点应该排在n的后面,所以从n后面继续比较
                    if ((c = cpr(cmp, key, n.key)) > 0) {
                        b = n;
                        n = f;
                        continue;
                    }
                    //如果键相等
                    if (c == 0) {
                        if (onlyIfAbsent || n.casValue(v, value)) {
                            @SuppressWarnings("unchecked") V vv = (V)v;
                            return vv;
                        }
                        break; // restart if lost race to replace value
                    }
                    // else c < 0; fall through
                }
                //如果n为null,说明b是链表的最后一个节点,
                //直接根据key,value,n创建一个新节点
                z = new Node<K,V>(key, value, n);
                //原子替换next域
                if (!b.casNext(n, z))
                    break;         // restart if lost race to append to b
                break outer;
            }
        }
        //生成随机数,随机提拔节点
        int rnd = ThreadLocalRandom.nextSecondarySeed();
        //判断是否需要增加level
        if ((rnd & 0x80000001) == 0) {// test highest and lowest bits
            int level = 1, max;
            while (((rnd >>>= 1) & 1) != 0)
                ++level;

            Index<K,V> idx = null;
            //保存头节点
            HeadIndex<K,V> h = head;
            //如果level小于跳表的层级
            if (level <= (max = h.level)) {
                //为节点生成对应的Index节点
                for (int i = 1; i <= level; ++i)
                    //依次赋值Index节点,并赋值节点的down域
                    idx = new Index<K,V>(z, idx, null);
            }
            else { // try to grow by one level
                level = max + 1; // hold in array and later pick the one to use
                //生成Index节点的数组
                @SuppressWarnings("unchecked")Index<K,V>[] idxs =
                        (Index<K,V>[])new Index<?,?>[level+1];
                //依次生成Index节点,并赋值down域
                for (int i = 1; i <= level; ++i)
                    idxs[i] = idx = new Index<K,V>(z, idx, null);
                for (;;) {
                    //保存头节点
                    h = head;
                    //保存旧层级
                    int oldLevel = h.level;
                    if (level <= oldLevel) // lost race to add level
                        break;
                    HeadIndex<K,V> newh = h;
                    //保存头节点对应的Node节点
                    Node<K,V> oldbase = h.node;
                    //为每一层生成一个头节点
                    for (int j = oldLevel+1; j <= level; ++j)
                        newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j);
                    //原子交换头节点
                    if (casHead(h, newh)) {
                        //h重新赋值为最高层的头节点
                        h = newh;
                        //idx赋值为旧层级的头节点,将level设置为之前的层级
                        idx = idxs[level = oldLevel];
                        break;
                    }
                }
            }
            // find insertion points and splice in
            //插入Index节点
            splice: for (int insertionLevel = level;;) {
                //保存新跳表的层级
                int j = h.level;
                for (Index<K,V> q = h, r = q.right, t = idx;;) {
                    //头节点或者idx节点为空
                    if (q == null || t == null)
                        //跳出循环
                        break splice;
                    //如果right节点不为空
                    if (r != null) {
                        //保存r的node
                        Node<K,V> n = r.node;
                        // compare before deletion check avoids needing recheck
                        int c = cpr(cmp, key, n.key);
                        if (n.value == null) {
                            if (!q.unlink(r))
                                break;
                            r = q.right;
                            continue;
                        }
                        if (c > 0) {
                            q = r;
                            r = r.right;
                            continue;
                        }
                    }

                    if (j == insertionLevel) {
                        //r节点插入q与t之间
                        if (!q.link(r, t))
                            break; // restart
                        //t节点的值为null,需要删除
                        if (t.node.value == null) {
                            findNode(key);
                            break splice;
                        }
                        if (--insertionLevel == 0)
                            break splice;
                    }

                    if (--j >= insertionLevel && j < level)
                        t = t.down;
                    q = q.down;
                    r = q.right;
                }
            }
        }
        return null;
    }
时间: 2024-11-09 04:49:32

ConcurrentSkipListMap源码---JDK1.8的相关文章

死磕 java集合之ConcurrentSkipListMap源码分析——发现个bug

前情提要 点击链接查看"跳表"详细介绍. 拜托,面试别再问我跳表了! 简介 跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表. 跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找. 跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能. 存储结构 跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找. 源码分析 主要内部类 内部类跟存储结构结合着来看,大概能预测到代码的组织方式. // 数据节点,典型的单链表结构 static final

ConcurrentSkipListMap源码分析

看一下跳跃表的示意图,途中蓝色的为头节点,头节点指向的是普通索引节点 通过上图可以看到跳跃表的基本结构,下面分析一下普通索引节点和头节点的源码,可以发现头节点和普通索引节点的区别就是头节点有level的概念,而普通索引节点没有 static class Index<K,V> { //索引持有的数据节点 final Node<K,V> node; //下一层索引 final Index<K,V> down; //右侧索引 volatile Index<K,V>

CopyOnWriteArrayList 源码---JDK1.8

CopyOnWriteArrayList:通过copy一份以前元素的快照,是一种读写分离的并发策略,我们也可以称这种容器为"写时复制器".该集合适合读多写少的场景(读没有加锁,其他更新操作均有加锁). /** The lock protecting all mutators */ final transient ReentrantLock lock = new ReentrantLock(); /** The array, accessed only via getArray/setA

hashMap源码--JDK1.8

重要的filed 默认容量为16 /** * The default initial capacity - MUST be a power of two. * 建议容量为 2的n次幂 */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 默认负载因子 /** * The load factor used when none specified in constructor. */ static final float

【JUC】JDK1.8源码分析之ConcurrentSkipListMap(二)

一.前言 最近在做项目的同时也在修复之前项目的一些Bug,所以忙得没有时间看源代码,今天都完成得差不多了,所以又开始源码分析之路,也着笔记录下ConcurrentSkipListMap的源码的分析过程. 二.ConcurrentSkipListMap数据结构 抓住了数据结构,对于理解整个ConcurrentSkipListMap有很重要的作用,其实,通过源码可知其数据结构如下. 说明:可以看到ConcurrentSkipListMap的数据结构使用的是跳表,每一个HeadIndex.Index结

Linux源码安装jdk1.8详细步骤

在使用Linux操作系统,肯定避免不了使用java程序,然而使用java程序可定少不了jdk,有的时候使用yum安装的open jdk好多功能都异常,下面是源码jdk1.8安装的详细步骤,大家可以参考一下. 下载jdk1.8安装包:链接:https://pan.baidu.com/s/1FjhZh6svz_kbofduCt3qEA 密码:5iu9 解压tar包 tar zxf jdk-8u91-linux-x64.tar.gz -C /usr/loca 创建软连接注:保持好创建软连接的习惯,不仅

从Java源码的角度来分析HashMap与HashTable的区别

由于HashMap与HashTable都是用来存储Key-Value的键值对,所以经常拿来对比二者的区别,下面就从源码的角度来分析一下HashMap与HashTable的区别, 首先介绍一下两者的区别,然后再从源码分析. HahMap与HahTable两者主要区别: 1.继承的父类不同 <span style="font-size:18px;">public class HashMap<K, V> extends AbstractMap<K, V>

Java源码之LinkedList

Java源码之LinkedList 转载请注意出处:http://blog.csdn.net/itismelzp/article/details/51620311 一.LinkedList概述 本文采用jdk1.8进行分析. LinkedList实现了List,Deque接口的双向链表,实现了链表的所有可选操作,并且可有null值.查找某个值的时候必须从头到尾的遍历链表.它是非线程安全的,当多个线程结构化修改同一链表时需要加上同步处理.(程结构化修改包括:添加.删除,不包括:修改值)可使用Col

算法与数据结构 (八) HashMap源码

一  存储结构 static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next;} transient Node<K,V>[] table; 内部存储的单元如上所示,整体上就是数组加链表的桶状结构. 二  put操作 put(key,value)内部调用的是putVal() 下面是源码  jdk1.8采用的是尾插法