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.AtomicLongjava.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

LongAddera 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.longadd(long)sum()AtomicLongLongAdderLongAdderJDK1.8APIAtomicLong

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.LongAdderthere 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#sumjava.util.concurrent.atomic.LongAdder#intValuejava.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 msINFO-> 34.739 main 1,000,000,000
INFO-> 19.588 main 执行1次耗时:1,194 msINFO-> 19.588 main 100,000,000
INFO-> 07.095 main 执行1次耗时:441 msINFO-> 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 msINFO-> 29.628 main 1,000,000,000
INFO-> 45.557 main 执行1次耗时:4,600 msINFO-> 45.558 main 100,000,000
INFO-> 22.594 main 执行1次耗时:633 msINFO-> 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.LongAdderAtomicLong