in performance testing, the essential basis is multithreaded programming. multithread safety counting is a very common use case, and i used or before that, but in the recent in-depth study of multithreaded programming (as the number of threads increased), i found that knowledge needed to increase again.java.util.concurrent.atomic.AtomicLong
java.util.concurrent.atomic.AtomicInteger
as you come to perspective, here’s a look at basic usage and performance testing.java.util.concurrent.atomic.LongAdder
brief introduction
LongAdder
a set of variables is maintained that add up to type variables that are updated atomically. when update methods compete between threads, the set of variables can grow dynamically to slow the competition. the sum method returns the current sum on the variable that maintains the sum. in contrast, the performance of the two is similar in a low concurrency environment. however, in a high concurrency environment, there is a significantly higher throughput, but a higher spatial complexity (that is, a high memory footprint). it is beginning to appear, and what is provided can basically replace the original.long
add(long)
sum()
AtomicLong
LongAdder
LongAdder
JDK1.8
API
AtomicLong
basic approach
for counter functions, there are not three commonly used functions: the construction method, the counting method (increment and subtraction), and the statistical method (getting the value).
constructor method
java.util.concurrent.atomic.LongAdder
there is only one constructor:
/**
* Creates a new adder with initial sum of zero.
*/
public LongAdder() {
}
copy the code
the default value.0
counting method
the four offered here are: increase or decrease 1, increase or decrease any value. all relatively simple. a simple look at the source code is ready to go. here’s a reset method.java.util.concurrent.atomic.LongAdder
/**
* Resets variables maintaining the sum to zero. This method may
* be a useful alternative to creating a new adder, but is only
* effective if there are no concurrent updates. Because this
* method is intrinsically racy, it should only be used when it is
* known that no threads are concurrently updating.
*/
public void reset() {
Cell[] as = cells; Cell a;
base = 0L;
if (as != null) {
for (int i = 0; i < as.length; ++i) {
if ((a = as[i]) != null)
a.value = 0L;
}
}
}
copy the code
DUE TO THE DESIGN IDEA AND OPERATING MECHANISM, THIS IS NOT COMMONLY USED, AND IF A CERTAIN VALUE IS REACHED, IT IS RECOUNTED, AND IN MOST CASES IT DOES NOT MEET EXPECTATIONS. INCLUDING THE LATTER THERE IS ANOTHER METHOD IS THE SAME, BUT YOU CAN DO A TIMED FUNCTION TO OBTAIN THE STOCK RECOUNT, TO PUT IT BLUNTLY, IS THE QPS SAMPLER.reset()
reset()
java.util.concurrent.atomic.LongAdder#sumThenReset
statistics
at the core of statistical methods is that others are either based on this method. then convert the value to another type to return.java.util.concurrent.atomic.LongAdder#sum
java.util.concurrent.atomic.LongAdder#intValue
java.util.concurrent.atomic.LongAdder#longValue
/**
* Returns the current sum. The returned value is <em>NOT</em> an
* atomic snapshot; invocation in the absence of concurrent
* updates returns an accurate result, but concurrent updates that
* occur while the sum is being calculated might not be
* incorporated.
*
* @return the sum
*/
public long sum() {
Cell[] as = cells; Cell a;
long sum = base;
if (as != null) {
for (int i = 0; i < as.length; ++i) {
if ((a = as[i]) != null)
sum += a.value;
}
}
return sum;
}
copy the code
in the same way, this method is naturally not so real-time in performance testing. this problem needs to be avoided.
performance testing
write a simple performance test script below:
public static void main(String[] args) {
LongAdder adder = new LongAdder()
POOL_SIZE = 1000
def phaser = new Phaser(1)
time {
POOL_SIZE.times {
fun {
1000000.times {
adder.increment()
}
} , phaser
}
phaser.arriveAndAwaitAdvance()
}
output(formatLong(adder.longValue()))
}
copy the code
my test scenario was to fix 1000 threads and adjust the number of single threads. here are the test results:
INFO-> 34.738 main 执行1次耗时:11,088 ms
INFO-> 34.739 main 1,000,000,000
INFO-> 19.588 main 执行1次耗时:1,194 ms
INFO-> 19.588 main 100,000,000
INFO-> 07.095 main 执行1次耗时:441 ms
INFO-> 07.096 main 10,000,000
copy the code
here are the test results:java.util.concurrent.atomic.AtomicLong
INFO-> 29.627 main 执行1次耗时:30,570 ms
INFO-> 29.628 main 1,000,000,000
INFO-> 45.557 main 执行1次耗时:4,600 ms
INFO-> 45.558 main 100,000,000
INFO-> 22.594 main 执行1次耗时:633 ms
INFO-> 22.595 main 10,000,000
copy the code
IN CONTRAST, DECISIVELY CHANGED. PS: PERFORMANCE IS MUCH BETTER THAN PERFORMANCE ONLY WHEN THERE IS MORE COMPETITION. IN ADDITION, IT IS HONEST AND PRACTICAL.LongAdder
AtomicLong