Jdk1.8 JUC源码增量解析(2)-atomic-LongAdder和LongAccumulator
作者:大飞
功能简介:
- LongAdder是jdk1.8提供的累加器,基于Striped64实现。它常用于状态采集、统计等场景。AtomicLong也可以用于这种场景,但在线程竞争激烈的情况下,LongAdder要比AtomicLong拥有更高的吞吐量,但会耗费更多的内存空间。
- LongAccumulator和LongAdder类似,也基于Striped64实现。但要比LongAdder更加灵活(要传入一个函数接口),LongAdder相当于是LongAccumulator的一种特例。
源码分析:
- 先看一下LongAdder类,看下结构:
public class LongAdder extends Striped64 implements Serializable { private static final long serialVersionUID = 7249069246863182397L; /** * Creates a new adder with initial sum of zero. */ public LongAdder() { }
LongAdder继承了Striped64,本身没有任何域。
- 再看一下LongAdder的方法:
public void add(long x) { Cell[] as; long b, v; int m; Cell a; //如果cell表为null,会尝试将x累加到base上。 if ((as = cells) != null || !casBase(b = base, b + x)) { /* * 如果cell表不为null或者尝试将x累加到base上失败,执行以下操作。 * 如果cell表不为null且通过当前线程的probe值定位到的cell表中的Cell不为null。 * 那么尝试累加x到对应的Cell上。 */ boolean uncontended = true; if (as == null || (m = as.length - 1) < 0 || (a = as[getProbe() & m]) == null || !(uncontended = a.cas(v = a.value, v + x))) //或者cell表为null,或者定位到的cell为null,或者尝试失败,都会调用下面的Striped64中定义的longAccumulate方法。 longAccumulate(x, null, uncontended); } }
add方法逻辑很简单,先尝试将x累加到base上,失败的话再看看能不能从cell表中找到cell,找到的话再尝试将x累加到这个cell里面,还失败的话就调用longAccumulate方法,这个方法上篇分析Striped64的时候分析过。
/** * Equivalent to {@code add(1)}. */ public void increment() { add(1L); } /** * Equivalent to {@code add(-1)}. */ public void decrement() { add(-1L); }
递增和递减方法,不需要解释了。
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; }
sum方法就是获取当前LongAdder值的总和,包括base和cells value两部分。
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; } } }
重置方法,将base和cells value两部分值都置为0。
public long sumThenReset() { Cell[] as = cells; Cell a; long sum = base; base = 0L; if (as != null) { for (int i = 0; i < as.length; ++i) { if ((a = as[i]) != null) { sum += a.value; a.value = 0L; } } } return sum; }
获取总和后重置。
LongAdder间接继承了Number,看下相关的方法实现:
public long longValue() { return sum(); } public int intValue() { return (int)sum(); } public float floatValue() { return (float)sum(); } public double doubleValue() { return (double)sum(); }
LongAdder的序列化使用序列化代理模式:
private static class SerializationProxy implements Serializable { private static final long serialVersionUID = 7249069246863182397L; private final long value; SerializationProxy(LongAdder a) { value = a.sum(); } private Object readResolve() { LongAdder a = new LongAdder(); a.base = value; return a; } } private Object writeReplace() { return new SerializationProxy(this); } private void readObject(java.io.ObjectInputStream s) throws java.io.InvalidObjectException { throw new java.io.InvalidObjectException("Proxy required"); }
- 再看一下LongAccumulator类,先看结构:
public class LongAccumulator extends Striped64 implements Serializable { private static final long serialVersionUID = 7249069246863182397L; private final LongBinaryOperator function; private final long identity; public LongAccumulator(LongBinaryOperator accumulatorFunction, long identity) { this.function = accumulatorFunction; base = this.identity = identity; }
LongAccumulator和LongAdder不同,内部有一个函数接口和一个初始值。
- 再看LongAccumulator的方法:
public void accumulate(long x) { Cell[] as; long b, v, r; int m; Cell a; if ((as = cells) != null || (r = function.applyAsLong(b = base, x)) != b && !casBase(b, r)) { boolean uncontended = true; if (as == null || (m = as.length - 1) < 0 || (a = as[getProbe() & m]) == null || !(uncontended = (r = function.applyAsLong(v = a.value, x)) == v || a.cas(v, r))) longAccumulate(x, function, uncontended); } }
和LongAdder的add方法一样的逻辑。
public long get() { Cell[] as = cells; Cell a; long result = base; if (as != null) { for (int i = 0; i < as.length; ++i) { if ((a = as[i]) != null) result = function.applyAsLong(result, a.value); } } return result; }
将内部所有的零散值通过函数算出一个最终值。
public void reset() { Cell[] as = cells; Cell a; base = identity; if (as != null) { for (int i = 0; i < as.length; ++i) { if ((a = as[i]) != null) a.value = identity; } } } public long getThenReset() { Cell[] as = cells; Cell a; long result = base; base = identity; if (as != null) { for (int i = 0; i < as.length; ++i) { if ((a = as[i]) != null) { long v = a.value; a.value = identity; result = function.applyAsLong(result, v); } } } return result; }
注意这里和LongAdder不同,这里的重置会将base和cells value都重置成初始值-identity。
其他的Number方法和序列化方式和LongAdder一样。
代码解析完毕!
参见:Jdk1.8 JUC源码增量解析(1)-atomic-Striped64
参见:Jdk1.6 JUC源码解析(1)-atomic-AtomicXXX
相关推荐
java-jdk1.8-8u361-all-jdk-win-linux 该压缩包中包含jdk1.8-8u361下windows版本和linux版本,其包含快速安装包和对应的jdk压缩包版本,具体内容如下: jdk-8u361-linux-aarch64.rpm jdk-8u361-linux-i586.rpm jdk-8...
jdk1.8版本可用,本地测试成功,本地版本 java version "1.8.0_91" Java(TM) SE Runtime Environment (build 1.8.0_91-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)
适用平台:windows x64 jdk版本:1.8 安装方式:双击安装即可
Java jdk1.8说明文档,直接下载并拷贝到jdk目下 jdk1.8 doc(jdk-8u191-docs-all)
jdk1.8 jdk-8u5-windows-i586 32位官方正式版 jdk1.8 jdk-8u5-windows-i586 32位官方正式版
JDK1.8 Java 官方 jdk-8u181-windows-x64.rar
jdk1.8可用的dubbo-admin-2.5.4.rar,jdk1.8可用的dubbo-admin-2.5.4.rar
JDK1.8安装文件安装即可,非常Nice~ 步骤1:下载JDK 首先,您需要把当前资源下载下来节约到指定目录 步骤2:安装JDK 一旦下载完成,您需要运行安装程序来安装JDK。如果您下载的是压缩包,需要解压缩到您希望安装...
三部分: jdk-1.8-linux-64-01 jdk-1.8-linux-64-02 jdk-1.8-linux-64-03
Linux x64版本并下载jdk-8u212-linux-x64.tar.gz文件。 将下载的文件解压缩到您选择的目录中。 配置环境变量,使系统能够找到Java运行时环境。可以通过设置JAVA_HOME和PATH环境变量来实现。
Java-JDK1.8官方完整正版-windows-x64位,下载解压即可以安装使用
java开发工具jdk1.8:jdk-8u152-windows-x64。该资源为windows版本的jdk1.8,有需要可自行下载~
jdk1.8-32、jdk1.8-64
mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk1.8安装包!mac系统jdk...
JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具. JDK是学好Java的第一步。不管是你要学习java编程,还是要搭建jsp web开发环境,或者是android开发环境都离不开它. 毫无疑问,Java...
jdk-8u91-windows-i586,jdk1.8 32位官方正式版 jdk-8u91-windows-i586
适用平台:windows x64 jdk版本:1.8 安装方式:双击安装即可
java jdk1.8 jdk-8u333-linux-x64 安装包 java 环境 linux安装包 无需注册. 解压安装
jdk1.8安装包
分享java开发环境工具jdk1.8给需要的人,希望能帮到有需要的人。----------------------------------------