LongAdder详解
Posted 钢铁-程序猿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LongAdder详解相关的知识,希望对你有一定的参考价值。
文章目录
LongAdder
add方法
public void add(long x)
Cell[] as; long b, v; int m; Cell a;
if ((as = cells) != null || !casBase(b = base, b + x))
boolean uncontended = true;
if (as == null || (m = as.length - 1) < 0 ||
(a = as[getProbe() & m]) == null ||
!(uncontended = a.cas(v = a.value, v + x)))
longAccumulate(x, null, uncontended);
casBase
/**
* CASes the base field.
*/
final boolean casBase(long cmp, long val)
return UNSAFE.compareAndSwapLong(this, BASE, cmp, val);
- 1、如果Celsl未初始化,则会调用casBase方法即使用cas对base进行修改,如果修改成功,则返回,如果没有修改成功(存在竞争),则会进if判断里面.
- 2、如果存在竞争,修改不成功,LongAdder会尝试定位到其中的一个Cell,通过更新这个Cell的值来维护整体的value。
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
longAccumulate方法详解后面补充
总结
简单的讲:
- add 过程:
首先对 base 进行修改
修改失败,对 cells 进行初始化操作
初始化完成, 判断当前线程所在 cell 是否为 null
如果 为 null,则创建 ,不为 null,则进行修改 cell 的 value
修改失败的话,准备对 cells 数组进行扩容,不是立马扩容的. - 扩容的条件:(三个条件同时满足)
当前线程的 cell 第一次修改失败
“rehash” 后,换一个新的 cell 后还是失败
且能够获取锁,对当前 cells 进行操作, 才进行扩容
以上是关于LongAdder详解的主要内容,如果未能解决你的问题,请参考以下文章
Juc16_LongAdder引入原理Striped64分散热点思想深度解析LongAdder源码和AtomicLong区别