一、AtomicLong是利用了底層的CAS操做來提供併發性。
二、在併發量較低的環境下,線程衝突的機率比較小,自旋的次數不會不少。可是,高併發環境下,N個線程同時進行自旋操做,會出現大量失敗並不斷自旋的狀況,此時AtomicLong的自旋會成爲瓶頸。
三、AtomicLong中有個內部volatile變量value保存着實際的long值,全部的操做都是針對該變量進行。也就是說,高併發環境下,value變量實際上是一個熱點,也就是N個線程競爭一個熱點。java
一、LongAdder的基本思路就是分散熱點,將value值分散到一個數組中,不一樣線程會命中到數組的不一樣槽中,各個線程只對本身槽中的那個值進行CAS操做,這樣熱點就被分散了,衝突的機率就小不少。若是要獲取真正的long值,只要將各個槽中的變量值累加返回。
二、低併發、通常的業務場景下AtomicLong是足夠了。若是併發量不少,存在大量寫多讀少的狀況,那LongAdder可能更合適。apache
一、建立一個Maven工程,Pom.xml代碼以下數組
<?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>
二、啓動文件併發
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) // 測試方法平均執行時間,若是測試吞入量則換成Mode.Throughput @OutputTimeUnit(TimeUnit.MICROSECONDS) // 輸出結果的時間粒度爲微秒 public class Main { private static AtomicLong count = new AtomicLong(); private static LongAdder longAdder = new LongAdder(); @Benchmark @Threads(1) //單位時間內也,默認一秒啓動多少個線程進行測試 public void atolong(){ count.getAndIncrement(); //測試AtomicLong遞增方法 } @Benchmark @Threads(1) //單位時間內也,默認一秒啓動多少個線程進行測試 public void loadder(){ longAdder.increment();//測試LongAdder的遞增方法 } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .include(Main.class.getSimpleName()) .forks(1) .build(); new Runner(options).run(); } }
三、單線程下的性能對比maven
吞吐量:AtomicLong性能更好ide
平均消耗時間:AtomicLong耗時更小高併發
四、20個線程下的性能對比性能
吞吐量:LongAdder優點明顯測試
平均消耗時間:LongAdder優點明顯ui