JDK15源码(二):ConcurrentHashMap(插入元素、初始化、扩容、计数、树化)

Unsafe

ConcurrentHashMap使用Synchronized和CAS锁对线程进行并发控制。CAS锁,也就是自旋锁,即比较并交换。ConcurrentHashMap的CAS锁是使用jdk.internal.misc.Unsafe类实现的,而jdk.internal.misc.Unsafe实际是调用sun.misc.Unsafe。

sun.misc.Unsafe的无参构造函数是私有private的,所以不能直接通过new实例化的方式获得一个对象,只能通过反射的方式获取。sun.misc.Unsafe类提供了三个CAS方法:compareAndSwapInt、compareAndSwapLong和compareAndSwapObject,分别是对int、long和object类型的变量做比较交换。这三个方法都有4个入参,第一个参数表示要作用的对象,第二个参数表示要作用的变量,第三个参数表示期望值,第四个参数是修改变成的值,当变量的值与第三个参数相同时,才会将变量的值修改为第四个参数,如果修改成功会返回true,修改失败返回false。示例如下:

import sun.misc.Unsafe;
import java.lang.reflect.Field;
class Person {
    
    
    public int age;

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }
}

@Test
public void testUnsafe() {
    
    
    Field unsafeField = Unsafe.class.getDeclaredFields()[0];
    unsafeField.setAccessible(true);
    Person person = new Person();
    try {
    
    
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        //定义要作用在哪个变量上
        final long COUNT_OFFSET = unsafe.objectFieldOffset(person.getClass().getDeclaredField("age"));
        boolean b = unsafe.compareAndSwapInt(person, COUNT_OFFSET, 0, 1);
        System.out.println(b);
        System.out.println(person.getAge());
    } catch (Exception e) {
    
    
        e
        .printStackTrace();
    }
}

comparableClassFor(Object x)

假设对象x的Class类型为C,如果Class C实现了Comparable接口,Comparable有且仅有一个泛型参数,是这个类本身C,也就是:

class C implements Comparable<C>

调用ConcurrentHashMap的comparableClassFor()方法会返回C.class。

static Class<?> comparableClassFor(Object x) {
    
    
    //判断是否是Comparable的子类,如果不是直接返回null
    if (x instanceof Comparable) {
    
    
        Class<?> c; Type[] ts, as; ParameterizedType p;
        //如果参数x的Class类型是String,直接返回class java.lang.String
        if ((c = x.getClass()) == String.class) // bypass checks
            return c;
        //获取实现的父类接口类型    
        if ((ts = c.getGenericInterfaces()) != null) {
    
    
            //遍历接口类型
            for (Type t : ts) {
    
    
                //判断该接口是否实现了泛型 && 接口的类型对象是否是Comparable 
                // 泛型参数只有一个 && 泛型参数类型就是入参的Class类型
                if ((t instanceof ParameterizedType) &&
                    ((p = (ParameterizedType)t).getRawType() == Comparable.class) && (as = p.getActualTypeArguments()) != null &&
     as.length == 1 && as[0] == c)
                    return c;
            }
        }
    }
    return null;
}

Class的getGenericInterfaces()方法返回的是实现的接口的类型数组。

public Type[] getGenericInterfaces() {
    
    
    ClassRepository info = getGenericInfo();
    return (info == null) ?  getInterfaces() : info.getSuperInterfaces();
}

接口ParameterizedType继承了接口Type。ParameterizedType是带有类型参数的类型,即常说的泛型,如Collection。

Type[] getActualTypeArguments(); //返回一个Type数组,数组里是参数化类型的参数
Type getRawType();//返回声明此类型的类或接口

示例:

List<String> list = new ArrayList<String>();
Type[] genericInterfaces = list.getClass().getGenericInterfaces();
for(Type type:genericInterfaces) {
    
    
    if(type instanceof ParameterizedType) {
    
    
        ParameterizedType parameterizedType = (ParameterizedType) type;
        System.out.println(Arrays.asList(parameterizedType.getActualTypeArguments()));//[E]
        System.out.println(parameterizedType.getRawType());//interface java.util.List
    }
}

compareComparables(Class<?> kc, Object k, Object x)

compareComparables是用来比较两个对象的大小。如果x为空,或者类型不是kc,返回0。如果x不为空并且x的类型是kc,返回k.compareTo(x)的比较结果。

static int compareComparables(Class<?> kc, Object k, Object x) {
    
    
    return (x == null || x.getClass() != kc ? 0 :
            ((Comparable)k).compareTo(x));
}

ConcurrentHashMap插入元素

ConcurrentHashMap.put()方法会调用putVal()方法插入元素。putVal()方法的第三个布尔变量onlyIfAbsent如果为true,表示只有在不存在相同的元素(hashcode和key值相等)才允许插入。如果存在相同的元素,putVal()方法会返回旧值,否则,返回null。与HashMap不同的是,ConcurrentHashMap不支持null键和null值。

(1)如果数组为null或者长度为0,初始化数组。
(2)根据hash算出待插入元素存放在数组的下标,判断该下标是否存在元素,如果不存在,使用CAS锁直接插入元素。
(3)判断数组是否正在扩容,如果是,当前线程加入扩容。
(4)判断该下标位置上的元素与待插入元素的hash和key是否相等,如果相等,表示是同一个元素,直接返回。
(5)对该下标位置的元素进行Synchronized同步,遍历链表/红黑树,插入元素。链表使用尾插法。
(6)计数。

final V putVal(K key, V value, boolean onlyIfAbsent) {
    
    
    //如果key或者value为null,抛出空指针异常。
    if (key == null || value == null) throw new NullPointerException();
    //将高16位和低16位进行异或运算,目标是得到尽可能不同的值。
    int hash = spread(key.hashCode());
    int binCount = 0;
    for (Node<K,V>[] tab = table;;) {
    
    
        //i表示待插入元素放在数组位置的下标,f表示tab[i]的元素,n表示tab的长度
        //fh表示tab[i]元素的hash值,fk表示tab[i]元素的key,fv表示tab[i]元素的value值
        Node<K,V> f; int n, i, fh; K fk; V fv;
        if (tab == null || (n = tab.length) == 0)
            //当数组为空或者数组的长度为0,对数组进行初始化
            tab = initTable();
        else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
    
    
            //如果f为空,表示tab[i]没有存放元素,使用cas锁,期望值是null,最后替换为待插入节点(hash, key, value)
            if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value)))
                break; //跳出循环,向空槽中添加元素不会使用锁
        }
        else if ((fh = f.hash) == MOVED)
            //如果tab[i]的hash值是MOVED(-1),表示正在进行扩容,当前线程也会加入扩容
            tab = helpTransfer(tab, f);
        else if (onlyIfAbsent
                 && fh == hash
                 && ((fk = f.key) == key || (fk != null && key.equals(fk)))
                 && (fv = f.val) != null)
            //检查第一个节点不需要占用锁,onlyIfAbsent表示不存在才能添加
            //如果onlyIfAbsent为true,并且tab[i]的hash值等于待插入节点的hash值,并且tab[i]的key的地址或内容等于待插入节点的hash值,
            //并且tab[i]的value不为空,表示数组已经存在这个元素,直接返回。
            return fv;
        else {
    
    
            V oldVal = null;
            //对tab[i]的第一个节点做同步,相同数组不同的下标不会有影响。
            synchronized (f) {
    
    
                //判断tab[i]的元素是否是f,防止有其他线程做了修改
                if (tabAt(tab, i) == f) {
    
    
                    if (fh >= 0) {
    
    
                        //用于计算tab[i]存放元素的数量
                        binCount = 1;
                        for (Node<K,V> e = f;; ++binCount) {
    
    
                            K ek;
                            if (e.hash == hash &&
                                ((ek = e.key) == key ||
                                 (ek != null && key.equals(ek)))) {
    
    
                                //存在相同的元素,oldVal记录的是旧值。 
                                oldVal = e.val;
                                if (!onlyIfAbsent)
                                    //如果允许替换旧值,直接替换旧值。
                                    e.val = value;
                                break;
                            }
                            Node<K,V> pred = e;
                            //e执行自己的下一个节点,如果为空,表示到达了链表的尾部,直接插入新的元素。
                            if ((e = e.next) == null) {
    
    
                                //用的是尾插法,将待插入元素添加到链表尾部。
                                pred.next = new Node<K,V>(hash, key, value);
                                break;
                            }
                        }
                    }
                    else if (f instanceof TreeBin) {
    
    
                        //如果tab[i]节点是树节点。
                        Node<K,V> p;
                        binCount = 2;
                        //如果红黑树中已经存在该节点,putTreeVal返回该节点,否则返回null。
                        if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
                                                       value)) != null) {
    
    
                            //新值替换旧值                           
                            oldVal = p.val;
                            if (!onlyIfAbsent)
                                p.val = value;
                        }
                    }
                    else if (f instanceof ReservationNode)
                        throw new IllegalStateException("Recursive update");
                }
            }
            if (binCount != 0) {
    
    
                //如果tab[i]链表的长度大于TREEIFY_THRESHOLD,进行处理(扩容或者转成红黑树)
                if (binCount >= TREEIFY_THRESHOLD)
                    treeifyBin(tab, i);
                if (oldVal != null)
                    return oldVal;
                break;
            }
        }
    }
    //数量加1之后判断是否需要扩容
    addCount(1L, binCount);
    return null;
}

table数组初始化

table是存储插入元素的数组,会延迟初始化直到第一次插入。大小总是2的幂,允许迭代器直接访问。

transient volatile Node<K,V>[] table;

HashMap有一个加载因子属性,默认是0.75f,HashMap扩容的阈值是等于数组长度乘以加载因子,当数组存储的元素的数量大于阈值就会进行扩容。而ConcurrentHashMap有一个属性sizeCtl,用于ConcurrentHashMap数组初始化和扩容控制。如果为负,表示正在进行初始化或者扩容;-1表示初始化,否则-(1+扩容线程数)。创建时,可以将sizeCtl设置为要使用的初始数组大小,默认为0。初始化后,sizeCtl为下一次数组调整的阈值。

未初始化:sizeCtl=0:表示没有指定初始容量。sizeCtl>0:表示初始容量。
初始化中:sizeCtl=-1,标记作用,告知其他线程,正在初始化。
正常状态:sizeCtl=0.75n ,扩容阈值。
扩容中: sizeCtl < 0 : 表示有其他线程正在执行扩容。
sizeCtl = (resizeStamp(n) << RESIZE_STAMP_SHIFT) + 2 :表示此时只有一个线程在执行扩容

private transient volatile int sizeCtl;

Thread.yield()方法的作用是让出当前线程的CPU时间片,使正在运行中的线程变成就绪状态,并重新竞争CPU的调度权,它可能会获取到,也有可能被其他线程获取到。

private final Node<K,V>[] initTable() {
    
    
    Node<K,V>[] tab; int sc;
    while ((tab = table) == null || tab.length == 0) {
    
    
        //如果sizeCtl小于0,表示当前有线程正在进行初始化
        if ((sc = sizeCtl) < 0)
            Thread.yield(); // 当前线程释放cpu
        //使用CAS锁,将全局变量sizeCtl的值修改为-1
        else if (U.compareAndSetInt(this, SIZECTL, sc, -1)) {
    
    
            try {
    
    
                if ((tab = table) == null || tab.length == 0) {
    
    
                    //如果sc的值是0,设置为16
                    int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                    @SuppressWarnings("unchecked")
                    //创建新数组,并赋值
                    Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                    table = tab = nt;
                    //n >>> 2表示1/4的n,n - (n/4) = 0.75n
                    sc = n - (n >>> 2);
                }
            } finally {
    
    
                //sizeCtl表示阈值
                sizeCtl = sc;
            }
            break;
        }
    }
    return tab;
}

数组扩容

transferIndex是扩容索引,表示已经分配给扩容线程的table数组索引位置。transferIndex主要用来协调多个线程,并发安全地获取迁移任务(hash桶)。

private transient volatile int transferIndex;
final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
    
    
    Node<K,V>[] nextTab; int sc;
    //如果f节点属于ForwardingNode类型,表示对应的桶已经迁移完毕
    if (tab != null && (f instanceof ForwardingNode) && (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
    
    
        int rs = resizeStamp(tab.length) << RESIZE_STAMP_SHIFT;
        //sizeCtl的值小于0,表示正在进行扩容
        while (nextTab == nextTable && table == tab && (sc = sizeCtl) < 0) {
    
    
            //
            if (sc == rs + MAX_RESIZERS || sc == rs + 1 || transferIndex <= 0)
                break;
            //CAS锁修改sizeCtl的值    
            if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1)) {
    
    
                //迁移
                transfer(tab, nextTab);
                break;
            }
        }
        return nextTab;
    }
    return table;
}

获取可用的线程数。

static final int NCPU = Runtime.getRuntime().availableProcessors();
//将数据从旧数组迁移到新数组 
private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
    
    
    //n表示旧数组的长度,stride表示每次要迁移的hash桶的个数
    int n = tab.length, stride;
    //如果可用的线程数大于1,stride等于(n/8)除以NCPU的值;否则stride等于n
    //如果计算出来的stride小于MIN_TRANSFER_STRIDE(16),将stride设置为16,所以每次要迁移的hash桶的个数至少为16
    if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
        stride = MIN_TRANSFER_STRIDE;
    //如果新数组为null,要进行初始化    
    if (nextTab == null) {
    
             
        try {
    
    
            //创建新数组,长度扩大一倍
            @SuppressWarnings("unchecked")
            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
            //赋值给newTab
            nextTab = nt;
        } catch (Throwable ex) {
    
    
            sizeCtl = Integer.MAX_VALUE;
            return;
        }
        //将ConcurrentHashMap的变量属性nextTable的值设置为nextTab
        nextTable = nextTab;
        //迁移数据从旧数组的最右边开始
        transferIndex = n;
    }
    //nextn表示新数组的长度
    int nextn = nextTab.length;
    //ForwardingNode继承了Node类,ForwardingNode的构造方法将hash值设置为MOVED=1,同时将入参赋值给ConcurrentHashMap属性nextTable
    ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
    //advance表示当前线程是否需要继续转移数据
    boolean advance = true;
    //finishing表示当前线程的转移工作是否完成
    boolean finishing = false;
    //假设transferIndex = 32
    //线程A:nextIndex = 32, nextBound = 16,transferIndex = 16, bound = 16, i = 31, advance = false
    //线程B:nextIndex = 16, nextBound = 0,transferIndex = 0,bound = 0, i = 15,advance = false
    //线程C:--i = 14 > bound, advance = false
    for (int i = 0, bound = 0;;) {
    
    
        Node<K,V> f; int fh;
        while (advance) {
    
    
            int nextIndex, nextBound;
            if (--i >= bound || finishing)
                advance = false;
            else if ((nextIndex = transferIndex) <= 0) {
    
    
                i = -1;
                advance = false;
            }
            else if (U.compareAndSetInt
                     (this, TRANSFERINDEX, nextIndex,
                      nextBound = (nextIndex > stride ?
                                   nextIndex - stride : 0))) {
    
    
                bound = nextBound;
                i = nextIndex - 1;
                advance = false;
            }
        }
        if (i < 0 || i >= n || i + n >= nextn) {
    
    
            int sc;
            if (finishing) {
    
    
                nextTable = null;
                //把扩容迁移数据后的数组赋值给table。
                table = nextTab;
                //(n << 1) = 2n, (n >>> 1) = 0.5n,sizeCtl = 1.5n,扩容后的数组长度是2n,也就是2n * 0.75 = 1.5n
                sizeCtl = (n << 1) - (n >>> 1);
                return;
            }
            if (U.compareAndSetInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
    
    
                //当前不是只有一个线程在扩容
                if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
                    return;
                //只有一个线程时,表示完成。    
                finishing = advance = true;
                i = n; // recheck before commit
            }
        }
        else if ((f = tabAt(tab, i)) == null)
            //如果tab[i]为null,将tab[i]设置为forwardingNode,表示迁移数据完成
            advance = casTabAt(tab, i, null, fwd);
        else if ((fh = f.hash) == MOVED)
            //正在迁移数据
            advance = true; // already processed
        else {
    
    
            //对tab[i]桶同步
            synchronized (f) {
    
    
                //再次验证tab[i]是否等于f
                if (tabAt(tab, i) == f) {
    
    
                    //迁移到新数据组后,元素要么继续放在低位i,要么放在(i+n)位置上
                    Node<K,V> ln, hn;
                    //hash大于0表示是链表
                    if (fh >= 0) {
    
    
                        //fh & n 得到的结果是0或者1
                        int runBit = fh & n;
                        Node<K,V> lastRun = f;
                        //这个for循环是为了找出最后一段hash & n 不变的链表,这样最后一段链表就不需要重新创建结点了。
                        for (Node<K,V> p = f.next; p != null; p = p.next) {
    
    
                            int b = p.hash & n;
                            if (b != runBit) {
    
    
                                runBit = b;
                                lastRun = p;
                            }
                        }
                        
                        if (runBit == 0) {
    
    
                            //rubBit等于0表示元素放在nextTab[i]上
                            ln = lastRun;
                            hn = null;
                        }
                        else {
    
    
                            //runBit等于1表示元素放在nextTab[i+n]上
                            hn = lastRun;
                            ln = null;
                        }
                        //头插法,lastRun之前的节点hash & n不确定,所以需要全部迁移
                        for (Node<K,V> p = f; p != lastRun; p = p.next) {
    
    
                            int ph = p.hash; K pk = p.key; V pv = p.val;
                            if ((ph & n) == 0)
                                ln = new Node<K,V>(ph, pk, pv, ln);
                            else
                                hn = new Node<K,V>(ph, pk, pv, hn);
                        }
                        //低位链表放在i处
                        setTabAt(nextTab, i, ln);
                        //高位链表放在i+n处
                        setTabAt(nextTab, i + n, hn);
                        //在原table中设置ForwardingNode节点以提示该桶扩容完成。
                        setTabAt(tab, i, fwd);
                        advance = true;
                    }
                    else if (f instanceof TreeBin) {
    
    
                        //如果是红黑树
                        TreeBin<K,V> t = (TreeBin<K,V>)f;
                        TreeNode<K,V> lo = null, loTail = null;
                        TreeNode<K,V> hi = null, hiTail = null;
                        int lc = 0, hc = 0;
                        for (Node<K,V> e = t.first; e != null; e = e.next) {
    
    
                            int h = e.hash;
                            TreeNode<K,V> p = new TreeNode<K,V>
                                (h, e.key, e.val, null, null);
                            //尾插法 放在nextTab[i] 双向链表
                            if ((h & n) == 0) {
    
    
                                if ((p.prev = loTail) == null)
                                    lo = p;
                                else
                                    loTail.next = p;
                                loTail = p;
                                //lc表示存放在nextTab[i]上元素的数量
                                ++lc;
                            }
                            else {
    
    
                                //放在nextTab[i+n]
                                if ((p.prev = hiTail) == null)
                                    hi = p;
                                else
                                    hiTail.next = p;
                                hiTail = p;
                                //hc表示存在在nextTab[i+n]上元素的数量
                                ++hc;
                            }
                        }
                        //如果拆分后的树的节点数量已经少于6个就需要重新转化为链表
                        //如果hc等于0,表示tab[i]上全部数据都放在nextTab[i]上
                        ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :
                            (hc != 0) ? new TreeBin<K,V>(lo) : t;
                        //如果lc等于0,表示tab[i]上全部数据都放在nextTab[i+n]上   
                        hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :
                            (lc != 0) ? new TreeBin<K,V>(hi) : t;
                        setTabAt(nextTab, i, ln);
                        setTabAt(nextTab, i + n, hn);
                        setTabAt(tab, i, fwd);
                        advance = true;
                    }
                    else if (f instanceof ReservationNode)
                        throw new IllegalStateException("Recursive update");
                }
            }
        }
    }
}

链表树化

当数组的长度大于64,且某个桶的链表的长度大于等于8,会将这个桶的链表转成红黑树,目的是提高元素的查找速度。红黑树的查找时间是logN,而链表的查找时间是N/2。当N等于8时,logN < N/2。

static final int MIN_TREEIFY_CAPACITY = 64;

/**
 * 如果数组的长度小于64,进行扩容;
 * 否则,将tab[index]的链表转成红黑树
 */
private final void treeifyBin(Node<K,V>[] tab, int index) {
    
    
    //b保存的是tab[index],n是数组的长度
    Node<K,V> b; int n;
    //判断数组是否为空
    if (tab != null) {
    
    
        //判断数组的长度是否小于MIN_TREEIFY_CAPACITY(64)
        if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
            //扩容一倍
            tryPresize(n << 1);
        //如果链表已经转化成红黑树,节点的hash值会变成-2。
        //此时判断hash是否大于等于0,大于等于0表示还是链表    
        else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
    
    
            //对b进行同步
            synchronized (b) {
    
    
                //再次判断tab[index]是否还是等于b
                if (tabAt(tab, index) == b) {
    
    
                    //建立一个双向链表
                    //hd表示头节点,tl表示前驱节点
                    TreeNode<K,V> hd = null, tl = null;
                    for (Node<K,V> e = b; e != null; e = e.next) {
    
    
                        TreeNode<K,V> p =
                            new TreeNode<K,V>(e.hash, e.key, e.val,
                                              null, null);
                        if ((p.prev = tl) == null)
                            //没有前驱节点的时候,将头节点设置为当前节点
                            hd = p;
                        else
                            //否则将前驱节点的后继节点设置为当前节点
                            tl.next = p;
                        //最后将当前节点设置为前驱节点,继续下一层循环    
                        tl = p;
                    }
                    //new TreeBin(hd)是生成一棵红黑树,再将这颗树放在tab[index]位置上。
                    setTabAt(tab, index, new TreeBin<K,V>(hd));
                }
            }
        }
    }
}

ConcurrentHashMap计数加1

先来看下baseCount和CounterCell的定义:
baseCount记录的是整个哈希表中存储的结点的个数总和。ConcurrentHashMap对这个变量的操作是基于CAS的,在高并发的情况下,可能会更新失败,操作失败之后就会使用CounterCell数组进行计数,数组内的每个ConuterCell都是一个独立的计数单元。

注解@sun.misc.Contended用于解决伪共享问题。所谓伪共享,即是在同一缓存行(CPU缓存的基本单位)中存储了多个变量,当其中一个变量被修改时,就会影响到同一缓存行内的其他变量,导致它们也要跟着被标记为失效,其他变量的缓存命中率将会受到影响。解决伪共享问题的方法一般是对该变量填充一些无意义的占位数据,从而使它独享一个缓存行。

private transient volatile long baseCount;
private transient volatile CounterCell[] counterCells;
@jdk.internal.vm.annotation.Contended static final class CounterCell {
    
    
    volatile long value;
    CounterCell(long x) {
    
     value = x; }
}

sumCount()方法是用来统计哈希表的数量,ConcurrentHashMap的size()方法也是直接调用了sumCount()方法。

//统计baseCount和CounterCell每一个cell的value值的总和
final long sumCount() {
    
    
   //获取CounterCell数组
   CounterCell[] cs = counterCells;
    //获取baseCount变量的值
    long sum = baseCount;
    if (cs != null) {
    
    
        //如果CounterCell完成初始化不为空,就遍历统计每一个cell的value值。
        for (CounterCell c : cs)
            if (c != null)
                sum += c.value;
    }
    return sum;
}
private final void addCount(long x, int check) {
    
    
	//cs记录变量counterCells的值,b记录变量baseCount的值,s是CAS修改baseCount后的期望值
    CounterCell[] cs; long b, s;
    //如果counterCells为空或者CAS修改baseCount值失败
    if ((cs = counterCells) != null ||
        !U.compareAndSetLong(this, BASECOUNT, b = baseCount, s = b + x)) {
    
    
        //c是某个CounterCell,m是cs的最大下标索引,v是计算出的CounterCell的value值。
        CounterCell c; long v; int m;
        //uncontended表示修改cell的值是成功还是失败
        boolean uncontended = true;
        //如果cs为null,或者cs的长度等于0,或者CounterCell为null,或者CAS修改cell的值失败
        //ThreadLocalRandom.getProbe() 得到线程的探针哈希值,与m进行与运算获得在CounterCell数组的下标
        if (cs == null || (m = cs.length - 1) < 0 ||
            (c = cs[ThreadLocalRandom.getProbe() & m]) == null ||
            !(uncontended =
              U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))) {
    
    
            fullAddCount(x, uncontended);
            return;
        }
        //当check的值小于等于1,只需要判断CAS修改cell的value值是否成功
        if (check <= 1)
            return;
        s = sumCount();
    }
    //当check的值小于0时,不需要检查是否需要扩容
    if (check >= 0) {
    
    
        //tab记录哈希数组,n是哈希数组的长度,sc是扩容阈值,nt表示扩容后要迁移到的新数组
        Node<K,V>[] tab, nt; int n, sc;
       //如果哈希数组的数量大于等于扩容阈值,并且哈希数组不为空,并且哈希数组的长度小于最大容量上限
        while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
               (n = tab.length) < MAXIMUM_CAPACITY) {
    
    
            int rs = resizeStamp(n) << RESIZE_STAMP_SHIFT;
            if (sc < 0) {
    
    
                if (sc == rs + MAX_RESIZERS || sc == rs + 1 ||
                    (nt = nextTable) == null || transferIndex <= 0)
                    break;
                if (U.compareAndSetInt(this, SIZECTL, sc, sc + 1))
                    transfer(tab, nt);
            }
            else if (U.compareAndSetInt(this, SIZECTL, sc, rs + 2))
                //扩容
                transfer(tab, null);
            s = sumCount();
        }
    }
}
//获取CPU核心线程数
static final int NCPU = Runtime.getRuntime().availableProcessors();

private final void fullAddCount(long x, boolean wasUncontended) {
    
    
    int h;
    //如果调用ThreadLocalRandom.getProbe() 得到的线程的探针哈希值是0
    if ((h = ThreadLocalRandom.getProbe()) == 0) {
    
    
    	//调用ThreadLocalRandom.localInit()方法初始化当前线程的线程字段,指示生成线程本地seed值。
        ThreadLocalRandom.localInit();      
        //获取线程探针哈希值
        h = ThreadLocalRandom.getProbe();
        //
        wasUncontended = true;
    }
    boolean collide = false; 
    for (;;) {
    
    
        CounterCell[] cs; CounterCell c; int n; long v;
        if ((cs = counterCells) != null && (n = cs.length) > 0) {
    
    
            if ((c = cs[(n - 1) & h]) == null) {
    
    
                if (cellsBusy == 0) {
    
                
                    //创建一个CounterCell
                    CounterCell r = new CounterCell(x); 
                    //如果cellsBusy的值是0,并且CAS锁修改cellsBusy的值成功(期望值是0,最后修改为1)
                    if (cellsBusy == 0 &&
                        U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
    
    
                        //created表示是否已经创建
                        boolean created = false;
                        try {
    
     
                            CounterCell[] rs; int m, j;
                            //再次校验,将新创建的CounterCell赋值到rs[j]位置上
                            if ((rs = counterCells) != null &&
                                (m = rs.length) > 0 &&
                                rs[j = (m - 1) & h] == null) {
    
    
                                rs[j] = r;
                                //创建成功
                                created = true;
                            }
                        } finally {
    
    
                            //把cellBusy的值修改为0
                            cellsBusy = 0;
                        }
                        //创建成功跳出循环
                        if (created)
                            break;
                        //如果再次校验的时候,rs[j]位置不等于null,进入下一层循环    
                        continue; 
                    }
                }
                collide = false;
            }
            else if (!wasUncontended)       // CAS already known to fail
                wasUncontended = true;      // Continue after rehash
            else if (U.compareAndSetLong(c, CELLVALUE, v = c.value, v + x))
                break;
            else if (counterCells != cs || n >= NCPU)
                collide = false;            // At max size or stale
            else if (!collide)
                collide = true;
            else if (cellsBusy == 0 &&
                     U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
    
    
                try {
    
    
                    if (counterCells == cs) 
                        //扩容数组一倍,并复制数组
                        counterCells = Arrays.copyOf(cs, n << 1);
                } finally {
    
    
                    cellsBusy = 0;
                }
                collide = false;
                continue;                   // Retry with expanded table
            }
            //重新hash
            h = ThreadLocalRandom.advanceProbe(h);
        }
        //如果cellBusy的值是0,并且counterCells为null,并且CAS修改cellBusy的值为1成功
        else if (cellsBusy == 0 && counterCells == cs &&
                 U.compareAndSetInt(this, CELLSBUSY, 0, 1)) {
    
    
            //设置init值为false     
            boolean init = false;
            try {
    
                  
                //counterCells为null   
                if (counterCells == cs) {
    
    
                    //创建数量为2的CounterCell数组
                    CounterCell[] rs = new CounterCell[2];
                    //h & 1的结果为0或者1
                    rs[h & 1] = new CounterCell(x);
                    //将rs赋值给counterCells
                    counterCells = rs;
                    //设置init值为true
                    init = true;
                }
            } finally {
    
    
                //修改cellsBusy为0
                cellsBusy = 0;
            }
            //如果初始化成功,跳出循环
            if (init)
                break;
        }
        //CAS修改baseCount的值成功,跳出循环
        else if (U.compareAndSetLong(this, BASECOUNT, v = baseCount, v + x))
            break;
    }
}

参考

HashMap.comparableClassFor(Object x)方法解读
jdk1.8 hashmap.compareComparables方法解析
JDK8:HashMap源码解析:TreeNode类的find方法
jdk1.8 hashmap.tieBreakOrder方法解析
JAVA语言之ConcurrentHashMap1.8源码分析
ConcurrentHashMap源码分析(JDK8) 扩容实现机制
Map 大家族的那点事儿 ( 7 ) :ConcurrentHashMap ( 下 )
为并发而生的 ConcurrentHashMap(Java 8)
【Type】类型 ParameterizedType
ConcurrentHashMap分析(二)数据扩容

猜你喜欢

转载自blog.csdn.net/u012734723/article/details/111413930