Jdk1.8 JUC源码增量解析(2)-atomic-LongAdder和LongAccumulator

转载自 Jdk1.8 JUC源码增量解析(2)-atomic-LongAdder和LongAccumulator

功能简介:
  • LongAdder是jdk1.8提供的累加器,基于Striped64实现。它常用于状态采集、统计等场景。AtomicLong也可以用于这种场景,但在线程竞争激烈的情况下,LongAdder要比AtomicLong拥有更高的吞吐量,但会耗费更多的内存空间。
  • LongAccumulator和LongAdder类似,也基于Striped64实现。但要比LongAdder更加灵活(要传入一个函数接口),LongAdder相当于是LongAccumulator的一种特例。
源码分析:
  • 先看一下LongAdder类,看下结构:
  1. public class LongAdder extends Striped64 implements Serializable {  
  2.     private static final long serialVersionUID = 7249069246863182397L;  
  3.     /** 
  4.      * Creates a new adder with initial sum of zero. 
  5.      */  
  6.     public LongAdder() {  
  7.     }  
LongAdder继承了Striped64,本身没有任何域。
  • 再看一下LongAdder的方法:
  1. public void add(long x) {  
  2.     Cell[] as; long b, v; int m; Cell a;  
  3.     //如果cell表为null,会尝试将x累加到base上。  
  4.     if ((as = cells) != null || !casBase(b = base, b + x)) {  
  5.         /* 
  6.          * 如果cell表不为null或者尝试将x累加到base上失败,执行以下操作。 
  7.          * 如果cell表不为null且通过当前线程的probe值定位到的cell表中的Cell不为null。 
  8.          * 那么尝试累加x到对应的Cell上。 
  9.          */  
  10.         boolean uncontended = true;  
  11.         if (as == null || (m = as.length - 1) < 0 ||  
  12.             (a = as[getProbe() & m]) == null ||  
  13.             !(uncontended = a.cas(v = a.value, v + x)))  
  14.             //或者cell表为null,或者定位到的cell为null,或者尝试失败,都会调用下面的Striped64中定义的longAccumulate方法。  
  15.             longAccumulate(x, null, uncontended);  
  16.     }  
  17. }  

       add方法逻辑很简单,先尝试将x累加到base上,失败的话再看看能不能从cell表中找到cell,找到的话再尝试将x累加到这个cell里面,还失败的话就调用longAccumulate方法,这个方法上篇分析Striped64的时候分析过。 

 

  1. /** 
  2.  * Equivalent to {@code add(1)}. 
  3.  */  
  4. public void increment() {  
  5.     add(1L);  
  6. }  
  7. /** 
  8.  * Equivalent to {@code add(-1)}. 
  9.  */  
  10. public void decrement() {  
  11.     add(-1L);  
  12. }  

       递增和递减方法,不需要解释了。 


  1. public long sum() {  
  2.     Cell[] as = cells; Cell a;  
  3.     long sum = base;  
  4.     if (as != null) {  
  5.         for (int i = 0; i < as.length; ++i) {  
  6.             if ((a = as[i]) != null)  
  7.                 sum += a.value;  
  8.         }  
  9.     }  
  10.     return sum;  
  11. }  

       sum方法就是获取当前LongAdder值的总和,包括base和cells value两部分。 


  1. public void reset() {  
  2.     Cell[] as = cells; Cell a;  
  3.     base = 0L;  
  4.     if (as != null) {  
  5.         for (int i = 0; i < as.length; ++i) {  
  6.             if ((a = as[i]) != null)  
  7.                 a.value = 0L;  
  8.         }  
  9.     }  
  10. }  

       重置方法,将base和cells value两部分值都置为0。 


  1. public long sumThenReset() {  
  2.     Cell[] as = cells; Cell a;  
  3.     long sum = base;  
  4.     base = 0L;  
  5.     if (as != null) {  
  6.         for (int i = 0; i < as.length; ++i) {  
  7.             if ((a = as[i]) != null) {  
  8.                 sum += a.value;  
  9.                 a.value = 0L;  
  10.             }  
  11.         }  
  12.     }  
  13.     return sum;  
  14. }  
获取总和后重置。

       LongAdder间接继承了Number,看下相关的方法实现:

  1. public long longValue() {  
  2.      return sum();  
  3.  }  
  4.   
  5.  public int intValue() {  
  6.      return (int)sum();  
  7.  }  
  8.   
  9.  public float floatValue() {  
  10.      return (float)sum();  
  11.  }  
  12.   
  13.  public double doubleValue() {  
  14.      return (double)sum();  
  15.  }  

  

 

       LongAdder的序列化使用序列化代理模式:

  1. private static class SerializationProxy implements Serializable {  
  2.     private static final long serialVersionUID = 7249069246863182397L;  
  3.   
  4.     private final long value;  
  5.     SerializationProxy(LongAdder a) {  
  6.         value = a.sum();  
  7.     }  
  8.   
  9.     private Object readResolve() {  
  10.         LongAdder a = new LongAdder();  
  11.         a.base = value;  
  12.         return a;  
  13.     }  
  14. }  
  15.   
  16. private Object writeReplace() {  
  17.     return new SerializationProxy(this);  
  18. }  
  19.   
  20. private void readObject(java.io.ObjectInputStream s)  
  21.     throws java.io.InvalidObjectException {  
  22.     throw new java.io.InvalidObjectException("Proxy required");  
  23. }  

 

 

  • 再看一下LongAccumulator类,先看结构
  1. public class LongAccumulator extends Striped64 implements Serializable {  
  2.     private static final long serialVersionUID = 7249069246863182397L;  
  3.     private final LongBinaryOperator function;  
  4.     private final long identity;  
  5.   
  6.     public LongAccumulator(LongBinaryOperator accumulatorFunction,  
  7.                            long identity) {  
  8.         this.function = accumulatorFunction;  
  9.         base = this.identity = identity;  
  10.     }  
LongAccumulator和LongAdder不同,内部有一个函数接口和一个初始值。
  • 再看LongAccumulator的方法:
  1. public void accumulate(long x) {  
  2.     Cell[] as; long b, v, r; int m; Cell a;  
  3.     if ((as = cells) != null ||  
  4.         (r = function.applyAsLong(b = base, x)) != b && !casBase(b, r)) {  
  5.         boolean uncontended = true;  
  6.         if (as == null || (m = as.length - 1) < 0 ||  
  7.             (a = as[getProbe() & m]) == null ||  
  8.             !(uncontended =  
  9.               (r = function.applyAsLong(v = a.value, x)) == v ||  
  10.               a.cas(v, r)))  
  11.             longAccumulate(x, function, uncontended);  
  12.     }  
  13. }  

       和LongAdder的add方法一样的逻辑。 

 

  1. public long get() {  
  2.     Cell[] as = cells; Cell a;  
  3.     long result = base;  
  4.     if (as != null) {  
  5.         for (int i = 0; i < as.length; ++i) {  
  6.             if ((a = as[i]) != null)  
  7.                 result = function.applyAsLong(result, a.value);  
  8.         }  
  9.     }  
  10.     return result;  
  11. }  

       将内部所有的零散值通过函数算出一个最终值。 

 

  1. public void reset() {  
  2.     Cell[] as = cells; Cell a;  
  3.     base = identity;  
  4.     if (as != null) {  
  5.         for (int i = 0; i < as.length; ++i) {  
  6.             if ((a = as[i]) != null)  
  7.                 a.value = identity;  
  8.         }  
  9.     }  
  10. }  
  11.   
  12. public long getThenReset() {  
  13.     Cell[] as = cells; Cell a;  
  14.     long result = base;  
  15.     base = identity;  
  16.     if (as != null) {  
  17.         for (int i = 0; i < as.length; ++i) {  
  18.             if ((a = as[i]) != null) {  
  19.                 long v = a.value;  
  20.                 a.value = identity;  
  21.                 result = function.applyAsLong(result, v);  
  22.             }  
  23.         }  
  24.     }  
  25.     return result;  
  26. }  
注意这里和LongAdder不同,这里的重置会将base和cells value都重置成初始值-identity。
其他的Number方法和序列化方式和LongAdder一样。

       代码解析完毕! 

 

 

       参见:Jdk1.8 JUC源码增量解析(1)-atomic-Striped64

       参见:Jdk1.6 JUC源码解析(1)-atomic-AtomicXXX


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329155.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql 密码hash算法_如何用hash创建一个mySQL用户(‘sha256’,$salt.$password)?

我肯定错过了什么.我想为select-only事务设置数据库用户帐户,但mysql不允许我在创建用户帐户时选择密码的哈希方法.这失败了&#xff1a;GRANT SELECT ON myDB.* TO selectuserlocalhostIDENTIFIED BY hash(sha256, salted-myfakelongrandompasswordstring);错误1064(42000)&am…

为什么微软逐步转变为开源公司

微软目前拥有自己的 BSD Unix 操作系统&#xff0c;支持 Ubuntu 作为 Windows 10 的一个子系统&#xff0c;最近又将 Xamarin 软件开发工具包开源&#xff0c;所有这些意味着微软已不再是比尔盖茨和史蒂夫鲍尔默的微软了。 我知道这很难令人相信&#xff0c;但微软确实正大步走…

Jdk1.8 JUC源码增量解析(1)-atomic-Striped64

转载自 Jdk1.8 JUC源码增量解析(1)-atomic-Striped64功能简介&#xff1a;Striped64是jdk1.8提供的用于支持如Long累加器&#xff0c;Double累加器这样机制的基础类。Striped64的设计核心思路就是通过内部的分散计算来避免竞争(比如多线程CAS操作时的竞争)。Striped64内部包含…

java内部类选择题_java内部类详解(附相关面试题)

说起内部类这个词&#xff0c;想必很多人都不陌生&#xff0c;但是又会觉得不熟悉。原因是平时编写代码时可能用到的场景不多&#xff0c;用得最多的是在有事件监听的情况下&#xff0c;并且即使用到也很少去总结内部类的用法。今天我们就来一探究竟。一.内部类基础在Java中&am…

开源,新的平台之战

近日&#xff0c;OpenDaylight项目的执行总监Neela Jacques在文章《开源的转变&#xff1a;一种新的平台战争》 中提到&#xff1a;开源已经成为软件公司业务战略的关键&#xff0c;是一种新的平台之战。 多年来&#xff0c;开源软件似乎处于技术产业的边缘。而如今&#xff0c…

java下载图片到手机相册_Unity保存图片到Android手机且更新相册

Android 保存图片到设备前言:在许多的应用或游戏中,大多都有保存图片或者截图等等的功能,这篇文档我们的目的是通过 Unity 保存图片,并且调用 Andorid 中的更新相册的原生方法.流程步骤:编写更新相册的 Android 原生接口 -> Unity 编写保存图片逻辑以及调用更新相册 Android…

如何在 Java 中正确使用 wait, notify 和 notifyAll – 以生产者消费者模型为例

转载自 如何在 Java 中正确使用 wait, notify 和 notifyAll – 以生产者消费者模型为例 wait, notify 和 notifyAll&#xff0c;这些在多线程中被经常用到的保留关键字&#xff0c;在实际开发的时候很多时候却并没有被大家重视。本文对这些关键字的使用进行了描述。 在 Java 中…

.NET Core 使用Dapper 操作MySQL

.NET Core 使用Dapper 操作MySQL 数据库&#xff0c; .NET Core 使用Dapper。 目前官方没有出.NET Core MySQL 驱动&#xff0c;但是已经有第三方进行改动封装出.NET Core MySQL Connector 预览版。 Dapper 也已经出了 .NET Core 预览版。 Dapper dot net 是一个轻量型的ORM&a…

Angular 2与TypeScript概览

迄今为止&#xff0c;在创建Web应用方面&#xff0c;AngularJS是当前最为流行的JavaScript框架。如今&#xff0c;Angular 2和TypeScript通过一种非常类似于Java 8的语法&#xff0c;使真正面向对象的Web开发成为了主流。 据Google的工程主管Brad Green介绍&#xff0c;有130万…

正确使用 Volatile 变量

转载自 Java 理论与实践 - 正确使用 Volatile 变量 - volatile 变量使用指南Java 语言中的 volatile 变量可以被看作是一种 “程度较轻的 synchronized”&#xff1b;与 synchronized 块相比&#xff0c;volatile 变量所需的编码较少&#xff0c;并且运行时开销也较少&#xf…

java龟兔赛跑设计思路_JAVA程序设计(09)-----面对对象设计初级应用 龟兔赛跑

1.乌龟和兔子共有属性和方法 做成父类 避免重复代码package com.lovo;/*** 类&#xff1a; 动物* author Abe* 属性&#xff1a; 名字 步距 总距离 睡觉的日子*/public class Animal {protected String name;protected int step;protected int distance;protected int sleepDay…

16年国庆假期期间兼职所悟

2016年9月25日&#xff0c;学校放假了&#xff01;&#xff01;&#xff01; 学校放假11天&#xff0c;10月7号才开学&#xff0c;除了晚上上个夜班之外别的时间都在闲着&#xff0c;这么大的自己感觉闲着真不是滋味&#xff0c;于是开始疯狂的在58上找工作&#xff0c;心里想…

python flask项目过程_Python 开发过程遇到的问题

另一方面&#xff0c;也是因为时间原因&#xff0c;没有事先系统了解 python 的具体内容&#xff0c;所以开发过程中基本都是拿 java 的东西往 python 里面套。比如&#xff1a;某个功能用 java 的 ArrayList 可以解决&#xff0c;那 python 中有没有类似的东西呢&#xff1f;j…

Java 中的双重检查(Double-Check)

转载自 Java 中的双重检查&#xff08;Double-Check&#xff09; 在 Effecitve Java 一书的第 48 条中提到了双重检查模式&#xff0c;并指出这种模式在 Java 中通常并不适用。该模式的结构如下所示&#xff1a; public Resource getResource() { if (resource null) { …

使用 Autofac 进行依赖注入

先说下为什么翻译这篇文章&#xff0c;既定的方向是架构&#xff0c;然后为了学习架构就去学习一些架构模式、设计思想。 突然有一天发现依赖注入这种技能。为了使得架构可测试、易维护、可扩展&#xff0c;需要架构设计为松耦合类型&#xff0c;简单的说也就是解耦。为了解耦前…

组合的示例代码 java_java实现Composite组合模式的实例代码

//20210121写在前面&#xff1a;刚期末考试完&#xff0c;考了面向对象&#xff0c;里边儿有23个设计模式&#xff0c;我寻思着考完挨个儿实现一下&#xff0c;本文实现组合模式组合模式核心思想类似文件夹的概念&#xff0c;构件树形结构&#xff0c;树形有叶子结点和文件夹结…

Java中的ThreadPoolExecutor类

转载自 Java中的ThreadPoolExecutor类在前面的文章中&#xff0c;我们使用线程的时候就去创建一个线程&#xff0c;这样实现起来非常简便&#xff0c;但是就会有一个问题&#xff1a; 如果并发的线程数量很多&#xff0c;并且每个线程都是执行一个时间很短的任务就结束了&…

webpack 前端构建

一、建立简单的项目目录 1、创建 manager 根目录(作为项目根目录)2、执行 npm init&#xff0c;在根目录manager下自动生成 package.json文件3、npm install webpack --save-dev&#xff0c;在项目中安装 webpack npm包4、在根目录下 创建 webpack.config.js&#xff0c;所有的…

简析 .NET Core 构成体系

简析 .NET Core 构成体系Roslyn 编译器RyuJIT 编译器CoreCLR & CoreRTCoreFX(.NET Core Libraries).NET Core 代码开发、部署、运行过程总结 前文介绍了.NET Core 在整个.NET 平台所处的地位&#xff0c;以及与.NET Framework的关系(原文链接)&#xff0c;本文将详细介绍.N…

判断一个男人穷还是富,只看这几点!

转载至&#xff1a; 来源&#xff1a;甜蜜爸妈手记&#xff08;wxtm01&#xff09; 作者&#xff1a;甜甜妈 创业君 导读 千主意万主意&#xff0c;如果不行动&#xff0c;永远就只是个想法而已。好想法要配得上行动才行。 看看他的爱好一个有事业心男人&#xff0c;绝对不…