longaccumulate方法final void longaccumulate(long x, longbinaryoperator fn,                          boolean wasuncontended) {    int h;    if ((h = getprobe()) == 0) {        threadlocalrandom.current(); // force initialization        h = getprobe();        wasuncontended = true;    }    boolean collide = false;                // true if last slot nonempty    for (;;) {        cell[] as; cell a; int n; long v;        if ((as = cells) != null && (n = as.length) > 0) {            if ((a = as[(n - 1) & h]) == null) {                if (cellsbusy == 0) {       // try to attach new cell                    cell r = new cell(x);   // optimistically create                    if (cellsbusy == 0 && cascellsbusy()) {                        boolean created = false;                        try {               // recheck under lock                            cell[] rs; int m, j;                            if ((rs = cells) != null &&                                (m = rs.length) > 0 &&                                rs[j = (m - 1) & h] == null) {                                rs[j] = r;                                created = true;                            }                        } finally {                            cellsbusy = 0;                        }                        if (created)                            break;                        continue;           // slot is now non-empty                    }                }                collide = false;            }            else if (!wasuncontended)       // cas already known to fail                wasuncontended = true;      // continue after rehash            else if (a.cas(v = a.value, ((fn == null) ? v + x :                                         fn.applyaslong(v, x))))                break;            else if (n >= ncpu || cells != as)                collide = false;            // at max size or stale            else if (!collide)                collide = true;            else if (cellsbusy == 0 && cascellsbusy()) {                try {                    if (cells == as) {      // expand table unless stale                        cell[] rs = new cell[n << 1];                        for (int i = 0; i < n; ++i)                            rs[i] = as[i];                        cells = rs;                    }                } finally {                    cellsbusy = 0;                }                collide = false;                continue;                   // retry with expanded table            }            h = advanceprobe(h);        }        else if (cellsbusy == 0 && cells == as && cascellsbusy()) {            boolean init = false;            try {                           // initialize table                if (cells == as) {                    cell[] rs = new cell[2];                    rs[h & 1] = new cell(x);                    cells = rs;                    init = true;                }            } finally {                cellsbusy = 0;            }            if (init)                break;        }        else if (casbase(v = base, ((fn == null) ? v + x :                                    fn.applyaslong(v, x))))            break;                          // fall back on using base    }}
代码较长,我们分段来分析,首先介绍一下各部分的内容
第一部分:for循环之前的代码,主要是获取线程的hash值,如果是0的话就强制初始化
第二部分:for循环中第一个if语句,在cell数组中进行累加、扩容
第三部分:for循环中第一个else if语句,这部分的作用是创建cell数组并初始化
第四部分:for循环中第二个else if语句,当cell数组竞争激烈时尝试在base上进行累加
线程hash值int h; if ((h = getprobe()) == 0) {     threadlocalrandom.current(); // force initialization     h = getprobe();     wasuncontended = true;   // true表示没有竞争} boolean collide = false; // true if last slot nonempty 可以理解为是否需要扩容
这部分的核心代码是getprobe方法,这个方法的作用就是获取线程的hash值,方便后面通过位运算定位到cell数组中某个位置,如果是0的话就会进行强制初始化
初始化cell数组final void longaccumulate(long x, longbinaryoperator fn,                          boolean wasuncontended) {    // 省略...    for (;;) {        cell[] as; cell a; int n; long v;        if ((as = cells) != null && (n = as.length) > 0) {            // 省略...        }        else if (cellsbusy == 0 && cells == as && cascellsbusy()) {  // 获取锁            boolean init = false;  // 初始化标志            try {                           // initialize table                if (cells == as) {                    cell[] rs = new cell[2];  // 创建cell数组                    rs[h & 1] = new cell(x);  // 索引1位置创建cell元素,值为x=1                    cells = rs;   // cells指向新数组                    init = true;  // 初始化完成                }            } finally {                cellsbusy = 0;  // 释放锁            }            if (init)                break;  // 跳出循环        }        else if (casbase(v = base, ((fn == null) ? v + x :                                    fn.applyaslong(v, x))))            break;                          // fall back on using base    }}
第一种情况下cell数组为null,所以会进入第一个else if语句,并且没有其他线程进行操作,所以cellsbusy==0,cells==as也是true,cascellsbusy()尝试对cellsbusy进行cas操作改成1也是true。
首先创建了一个有两个元素的cell数组,然后通过线程h & 1 的位运算在索引1的位置设置一个value为1的cell,然后重新赋值给cells,标记初始化成功,修改cellsbusy为0表示释放锁,最后跳出循环,初始化操作就完成了。
对base进行累加final void longaccumulate(long x, longbinaryoperator fn,                          boolean wasuncontended) {    // 省略...    for (;;) {        cell[] as; cell a; int n; long v;        if ((as = cells) != null && (n = as.length) > 0) {            // 省略...        }        else if (cellsbusy == 0 && cells == as && cascellsbusy()) {            // 省略...        }        else if (casbase(v = base, ((fn == null) ? v + x :                                    fn.applyaslong(v, x))))            break;                          // fall back on using base    }}
第二个else if语句的意思是当cell数组中所有位置竞争都很激烈时,就尝试在base上进行累加,可以理解为最后的保障
cell数组初始化之后final void longaccumulate(long x, longbinaryoperator fn,                          boolean wasuncontended) {    // 省略...    for (;;) {        cell[] as; cell a; int n; long v;        if ((as = cells) != null && (n = as.length) > 0) {  // as初始化之后满足条件            if ((a = as[(n - 1) & h]) == null) {  // as中某个位置的值为null                if (cellsbusy == 0) {       // try to attach new cell 是否加锁                    cell r = new cell(x);   // optimistically create 创建新cell                    if (cellsbusy == 0 && cascellsbusy()) { // 双重检查是否有锁,并尝试加锁                        boolean created = false;  //                         try {               // recheck under lock                            cell[] rs; int m, j;                            if ((rs = cells) != null &&                                (m = rs.length) > 0 &&                                rs[j = (m - 1) & h] == null) {  // 重新检查该位置是否为null                                rs[j] = r;  // 该位置添加cell元素                                created = true;  // 新cell创建成功                            }                        } finally {                            cellsbusy = 0;  // 释放锁                        }                        if (created)                            break;  // 创建成功,跳出循环                        continue;           // slot is now non-empty                    }                }                collide = false;  // 扩容标志            }            else if (!wasuncontended)       // 上面定位到的索引位置的值不为null                wasuncontended = true;      // 重新计算hash,重新定位其他索引位置重试            else if (a.cas(v = a.value, ((fn == null) ? v + x :                                         fn.applyaslong(v, x))))  // 尝试在该索引位置进行累加                break;            else if (n >= ncpu || cells != as)  // 如果数组长度大于等于cpu核心数,就不能在扩容                collide = false;            // at max size or stale            else if (!collide)  // 数组长度没有达到最大值,修改扩容标志可以扩容                collide = true;            else if (cellsbusy == 0 && cascellsbusy()) { // 尝试加锁                try {                    if (cells == as) {      // expand table unless stale                        cell[] rs = new cell[n << 1];  // 创建一个原来长度2倍的数组                        for (int i = 0; i < n; ++i)                            rs[i] = as[i];  // 把原来的元素拷贝到新数组中                        cells = rs;  // cells指向新数组                    }                } finally {                    cellsbusy = 0;  // 释放锁                }                collide = false;  // 已经扩容完成,修改标志不用再扩容                continue;                   // retry with expanded table            }            h = advanceprobe(h);  // 重新获取hash值        }        // 省略...}
根据代码中的注释分析一遍整体逻辑
首先如果找到数组某个位置上的值为null,说明可以在这个位置进行操作,就创建一个新的cell并初始化值为1放到这个位置,如果失败了就重新计算hash值再重试
定位到的位置已经有值了,说明线程之间产生了竞争,如果wasuncontended是false就修改为true,并重新计算hash重试
定位的位置有值并且wasuncontended已经是true,就尝试在该位置进行累加
当累加失败时,判断数组容量是否已经达到最大,如果是就不能进行扩容,只能rehash并重试
如果前面条件都不满足,并且扩容标志collide标记为false的话就修改为true,表示可以进行扩容,然后rehash重试
首先尝试加锁,成功了就进行扩容操作,每次扩容长度是之前的2倍,然后把原来数组内容拷贝到新数组,扩容就完成了。
以上就是java并发编程中longadder的执行情况是怎样的的详细内容。
   
 
   