The difference between AtomicLong and Long Adder
AtomicLong
1. AtomicLong uses the underlying CAS operations to provide concurrency.
2. In the environment of low concurrency, the probability of thread collision is relatively small, and the number of spins is not much. However, in high concurrent environment, N threads spin simultaneously, which will result in a large number of failures and continuous spinning. At this time, AtomicLong's spin will become a bottleneck.
3. There is an internal volatile variable value in AtomicLong that holds the actual long value. All operations are directed at that variable. That is to say, in high concurrency environment, value variable is actually a hot spot, that is, N threads compete for a hot spot.
LongAdder
1. The basic idea of LongAdder is to disperse the hot spots. Divide the value into an array. Different threads will hit different slots in the array. Each thread only CAS the value in its own slot, so the hot spots will be dispersed and the probability of conflict will be much smaller. If you want to get the true long value, just add the values of variables in each slot back.
2. AtomicLong is sufficient for low concurrency and general business scenarios. LongAdder may be more appropriate if there is a lot of concurrency and a lot of writing and reading.
Testing the performance of AtomicLong and LongAdder with JMH
1. Create a Maven project with Pom.xml code as follows
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.jane</groupId> <artifactId>jmh1</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!-- JMH --> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-core</artifactId> <version>1.20</version> </dependency> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-generator-annprocess</artifactId> <version>1.20</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <executions> <execution> <id>run-benchmarks</id> <phase>integration-test</phase> <goals> <goal>exec</goal> </goals> <configuration> <classpathScope>test</classpathScope> <executable>java</executable> <arguments> <argument>-classpath</argument> <classpath /> <argument>org.openjdk.jmh.Main</argument> <argument>.*</argument> </arguments> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
2. Startup file
package com.jane; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.LongAdder; @BenchmarkMode(Mode.AverageTime) // The average execution time of the test method is changed to Mode.Throughput if swallowed. @OutputTimeUnit(TimeUnit.MICROSECONDS) // The time granularity of the output is microsecond public class Main { private static AtomicLong count = new AtomicLong(); private static LongAdder longAdder = new LongAdder(); @Benchmark @Threads(1) //How many threads are started per second by default for testing public void atolong(){ count.getAndIncrement(); //Testing AtomicLong Incremental Method } @Benchmark @Threads(1) //How many threads are started per second by default for testing public void loadder(){ longAdder.increment();//Testing LongAdder Incremental Method } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .include(Main.class.getSimpleName()) .forks(1) .build(); new Runner(options).run(); } }
3. Performance comparison under single thread
Throughput: AtomicLong performs better
Average time consumed: AtomicLong takes less time
Performance comparison under 4 and 20 threads
Throughput: LongAdder has obvious advantages
Average consumption time: LongAdder has obvious advantages