Let’s analyze its basic implementation process based on the source code.
This class is usually preferable to AtomicLong when multiple threads update a common sum that is used for purposes such as collecting statistics, not for fine-grained synchronization control. Under low update contention, the two classes have similar characteristics. But under high contention, expected throughput of this class is significantly higher, at the expense of higher space consumption.
The above paragraph is from the LongAdder
source code comment Part of it, translated roughly means
This class is generally preferred over AtomicLong
when multiple threads update a common sum that is used to collect statistics but not for the purpose of fine-grained synchronization control. Under low update contention, these two classes have similar characteristics. But under high contention conditions, the expected throughput of this class is significantly higher, but at the cost of higher space consumption.
That is to sayLongAdder
is more efficient when the concurrency is high, but the cost is to trade space for time.
Let’s explain the principle of LongAdder
in a simple way: when there is little concurrency, it is enough to perform the accumulation operation on only one variable base
, so and AtomicLong
is similar; but when the concurrency increases, if you still operate on the variable base
, many threads will be blocked, so create an array cells
, in Each element of the array can be accumulated. When calculating the final result, just calculate the sum of each element of the base
and cells
arrays. The specific bit in the array where the thread operates can be determined by calculating hash
to determine the index position.
LongAdder
Attributes inherited from the parent class Striped64
, here Cell
is used to The internal class of the accumulation operation has an internal value
attribute to store the accumulated value.
// CPU核心数 static final int NCPU = Runtime.getRuntime().availableProcessors(); // 并发高时进行累加的Cell数组 transient volatile Cell[] cells; // 多个线程没有竞争时在base上进行累加 transient volatile long base; // Cell数组是否正在创建或扩容 transient volatile int cellsBusy;
Accumulation operation methodincrement()
The actual call is add(1L)
, so let’s look directly at the add
method
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); } }
Let’s first look at the first if
statement. Under initial conditions, cells
is null
, so the casBase
operation will be performed. That is to say, accumulation is performed on the base
variable. If the operation is successful, it means there is no competition at present, so it is over.
When the concurrency increases, the casBase
method may fail, so at this time, the second if
statement judgment is entered.
When it comes in for the first time, the Cell
arrayas
is null
, so longAccumulate# will be executed. ##, initialize the
Cell array
as and accumulate
1 at index
1;
if statement
as, it will not be
null, and the array length is also greater than
0
a = as[getProbe() & m]) == null, the simple understanding of this sentence is to randomly find an index in the array
as Position, determine whether the value of the position is
null, if it is
null, execute
longAccumulate, if not
null, continue to judge
!(uncontended = a.cas(v = a.value, v x))This sentence means that the accumulation operation is performed at the found index position , if successful, end the operation, if failed, execute
longAccumulate
The above is the detailed content of LongAdder source code analysis of Java concurrent programming. For more information, please follow other related articles on the PHP Chinese website!