jdk源码解析--LongAdder类

Posted 我的IT技术路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk源码解析--LongAdder类相关的知识,希望对你有一定的参考价值。

在之前介绍的抽象类Striped64中,我们知道这个类是为了计数器而设计的,在jdk中有LongAdderLongAccumulatorDoubleAdderDoubleAccumulator四个类继承了Striped64类,以**Adder为结尾的是累加器,实现的是一种以初始值为0的累加效果,而以**Accumulator为结尾的是计数器,有着更灵活的操作,初始值不一定为0,实现的方式也不一定是累加,亦可以是相乘等其他操作。换句话说累加器是计数器的一种特殊实现。本文主要讲解的是LongAdder。现在我们通过一个demo来看下累加器的应用。

1. import java.util.concurrent.atomic.LongAdder;  

2. import java.util.stream.IntStream;  

3.   

4. public class LongAdderTest {  

5.   

6.     public static void main(String[] args) {  

7.         LongAdder longAdder = new LongAdder();  

8.         IntStream.range(0,100).forEach(i->  

9.                 new Thread(new AddTest(longAdder)).start());  

10.     }  

11.   

12.     private static class AddTest implements Runnable{  

13.         private LongAdder adder;  

14.   

15.         public AddTest(LongAdder adder) {  

16.             this.adder = adder;  

17.         }  

18.   

19.         @Override  

20.         public void run() {  

21.             adder.add(1);//这个是原子性的,能保证最后累加的结果是正确的  

22.             System.out.println(Thread.currentThread().getName()+" get sum is "+adder.sum());//这个是返回当前的总和,是一个当前线程获取到的一个快照  

23.         }  

24.     }  

25. }  

看上去和AtomicLong的的使用没什么差别,但在多线程高并发的情况下效率上会比较高。

下面我们可以看下这个类的具体实现:

1. public class LongAdder extends Striped64 implements Serializable {  

2.     private static final long serialVersionUID = 7249069246863182397L;  

3.     public LongAdder() {  

4.     }  

5.     public void add(long x) {  

6.         Cell[] as; long b, v; int m; Cell a;  

7.         if ((as = cells) != null || !casBase(b = base, b + x)) {//cas设置base操作不成功  

8.             boolean uncontended = true;  

9.             if (as == null || (m = as.length - 1) < 0 ||//as为空或者长度小于0  

10.                 (a = as[getProbe() & m]) == null ||   //或者该位置为空  

11.                 !(uncontended = a.cas(v = a.value, v + x)))//是否发生竞争  

12.                 longAccumulate(x, null, uncontended);  

13.         }  

14.     }  

15.     public void increment() {  

16.         add(1L);  

17.     }  

18.     public void decrement() {  

19.         add(-1L);  

20.     }  

21.     public long sum() {//获取当前的值,没有加锁,只是获取当时的快照值  

22.         Cell[] as = cells; Cell a;  

23.         long sum = base;  

24.         if (as != null) {  

25.             for (int i = 0; i < as.length; ++i) {  

26.                 if ((a = as[i]) != null)  

27.                     sum += a.value;  

28.             }  

29.         }  

30.         return sum;  

31.     }  

32.     public void reset() {//重置  

33.         Cell[] as = cells; Cell a;  

34.         base = 0L;  

35.         if (as != null) {  

36.             for (int i = 0; i < as.length; ++i) {  

37.                 if ((a = as[i]) != null)  

38.                     a.value = 0L;  

39.             }  

40.         }  

41.     }  

42.     public long sumThenReset() {//求和后重置,返回求和后的值  

43.         Cell[] as = cells; Cell a;  

44.         long sum = base;  

45.         base = 0L;  

46.         if (as != null) {  

47.             for (int i = 0; i < as.length; ++i) {  

48.                 if ((a = as[i]) != null) {  

49.                     sum += a.value;  

50.                     a.value = 0L;  

51.                 }  

52.             }  

53.         }  

54.         return sum;  

55.     }  

56.      

57. }  

上面的实现还是比较简单,核心在上一文中的Striped64中介绍。本文就介绍到这里,下一节我们看下计数器的实现。


以上是关于jdk源码解析--LongAdder类的主要内容,如果未能解决你的问题,请参考以下文章

JDK 源码分析 -- LongAdder

JDK 源码分析 -- LongAdder

Java并发编程之LongAdder和LongAccumulator源码探究

jdk1.8 LongAdder 难点解析

Java8原子弹类之LongAdder源码分析

Java Review - 并发编程_JDK 8新增的原子操作类LongAdder & LongAccumulator