LongAccumulator和DoubleAccumulator类如何工作?

Java 8中的两个新类值得关注: LongAccumulatorDoubleAccumulator 。 它们旨在安全地跨线程安全地累积 (稍后将进一步说明)。 一个测试值一千个单词,所以它是这样工作的:

class AccumulatorSpec extends Specification {public static final long A = 1public static final long B = 2public static final long C = 3public static final long D = -4public static final long INITIAL = 0Ldef 'should add few numbers'() {given:LongAccumulator accumulator = new LongAccumulator({ long x, long y -> x + y }, INITIAL)when:accumulator.accumulate(A)accumulator.accumulate(B)accumulator.accumulate(C)accumulator.accumulate(D)then:accumulator.get() == INITIAL + A + B + C + D}

因此,累加器采用二进制运算符并将初始值与每个累加值组合在一起。 这意味着((((0 + 1) + 2) + 3) + -4)等于2 。 别走开,还有更多。 累加器也可以采用其他运算符,如以下用例所示:

def 'should accumulate numbers using operator'() {given:LongAccumulator accumulator = new LongAccumulator(operator, initial)when:accumulator.accumulate(A)accumulator.accumulate(B)accumulator.accumulate(C)accumulator.accumulate(D)then:accumulator.get() == expectedwhere:operator                 | initial           || expected{x, y -> x + y}          | 0                 || A + B + C + D{x, y -> x * y}          | 1                 || A * B * C * D{x, y -> Math.max(x, y)} | Integer.MIN_VALUE || max(A, B, C, D){x, y -> Math.min(x, y)} | Integer.MAX_VALUE || min(A, B, C, D)
}

显然,累加器在设计用于繁重的多线程环境下也能正常工作。 现在的问题是, LongAccumulator中允许进行其他哪些操作(这也适用于DoubleAccumulator ),为什么? JavaDoc这次不是很正式(粗体):

不能保证并且不能依赖于线程内或线程间的累加顺序,因此此类仅适用于累加顺序无关紧要的函数。 所提供的累加器功能应无副作用 ,因为当尝试更新由于线程间争用而失败时,可以重新应用该累加器功能 。 应用该函数时,将当前值作为其第一个参数,并将给定的update作为第二个参数。

为了了解LongAccumulator工作原理,允许哪种类型的操作以及为何如此之快(因为与AtomicLong相比,它是如此之快),让我们从后面开始get()方法:

transient volatile long base;
transient volatile Cell[] cells;private final LongBinaryOperator function;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 long get() {long result = base;for (Cell cell : cells)result = function.applyAsLong(result, cell.value);return result;
}

甚至在功能上没有内部状态:

public long get() {return Arrays.stream(cells).map(s -> s.value).reduce(base, function::applyAsLong);
}

我们清楚地看到有一些内部cells数组,最后我们必须遍历该数组并将操作符函数顺序应用于每个元素。 事实证明, LongAccumulator具有两种用于累加值的机制:单个base计数器和在锁线程争用较高的情况下的值数组。 如果在没有锁争用的情况下使用LongAccumulator ,则仅使用单个volatile base变量和CAS操作,就像在AtomicLong 。 但是,如果CAS失败,则此类退回到一组值。 您不想看到实现,它有90行,有时会有8个嵌套层。 您需要知道的是,它使用简单的算法始终将给定线程分配给同一单元(提高了缓存的局部性)。 从现在开始,该线程具有其自己的,几乎是私有的计数器副本。 它与其他几个线程共享此副本,但并非与所有其他线程共享-它们具有自己的单元。 因此,最终您得到的是必须汇总的半计算计数器数组。 这就是您在get()方法中看到的。

这又使我们想到一个问题, LongAccumulator中允许使用LongAccumulator op符( op )。 我们知道在低负载下相同的累积顺序将导致:

((I op A) op B)  //get()

这意味着所有值都聚集在基本变量中,并且不使用任何计数器数组。 但是,在高负载下, LongAccumulator会将工作分解为两个铲斗(单元),然后LongAccumulator铲斗也进行蓄积:

(I op A)              //cell 1
(I op B)              //cell 2(I op A) op (I op B)  //get()

或相反亦然:

(I op B)              //cell 1
(I op A)              //cell 2(I op B) op (I op A)  //get()

显然,所有对get()调用都应产生相同的结果,但这都取决于所提供的op符的属性( +*max等)。

可交换的

我们无法控制单元的顺序及其分配方式。 这就是((I op A) op (I op B))((I op B) op (I op A))必须返回相同结果的原因。 更紧凑地说,我们正在寻找这样的运算符op ,其中每个XY X op Y = Y op X 这意味着op必须是可交换的

中性元素(身份)

单元格使用标识(初始)值I进行逻辑初始化。 我们无法控制单元的数量和顺序,因此身份值可​​以按任意顺序多次应用。 但这是一个实现细节,因此不应影响结果。 更确切地说,对于每个X和任何op

X op I = I op X = X

这意味着对于运算符op每个参数X ,标识(初始)值I必须为中性值。

关联性

假设我们有以下单元格:

I op A                              // cell 1
I op B                              // cell 2
I op C                              // cell 3
((I op A) op (I op B)) op (I op C)  //get()

但是下一次他们的布置有所不同

I op C                              // cell 1
I op B                              // cell 2
I op A                              // cell 2
((I op C) op (I op B)) op (I op A)  //get()

知道op是可交换的,而I是中性元素,我们可以证明(对于每个ABC ):

((I op A) op (I op B)) op (I op C) = ((I op C) op (I op B)) op (I op A)
(A op B) op C = (C op B) op A
(A op B) op C = A op (B op C)

这证明op必须具有关联性LongAccumulator才能真正起作用。

包起来

LongAccumulatorDoubleAccumulator是JDK 8中新增的高度专业化的类。JavaDoc相当荒谬,但是我们尝试证明操作员和初始值必须满足的属性才能使它们完成工作。 我们知道运算符必须是关联的可交换的并且具有中性元素。 如果JavaDoc明确声明它必须是阿贝尔的类半体动物 ;-),那就更好了。 然而,出于实际目的,这些累加器仅用于加,乘,最小和最大值,因为它们是唯一发挥良好作用的有用运算符(带有适当的中性元素)。 例如,减法和除法不是关联和可交换的,因此不可能工作。 更糟的是,累加器只会表现得不确定。

翻译自: https://www.javacodegeeks.com/2015/06/how-longaccumulator-and-doubleaccumulator-classes-work.html

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

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

相关文章

jQuery 利用 $.getJson() 实现跨域

数据量不大时&#xff0c;跨域的不二之选&#xff0c;而且操作简单&#xff0c;易上手。 a.com/test.html //这里我假定有一些数据&#xff1a; var formData form.serialize(); //这里的jsoncallback 是一个回调函数名 &#xff0c;是必须的参数 //wrand保证每次请求不一样&a…

centos7创建asm磁盘_ASM环境下防止误将数据文件扩容到本地文件系统的方法

前言时常会接到客户或一线工程师反馈oracle数据库报“ora-01110”等错误&#xff0c;本人过往也处理过好几次类似的故障&#xff0c;发现基本上是由于开发人员或初级维护人员在执行数据库表空间扩容时&#xff0c;不小心将本身需要扩容到ASM磁盘组的数据文件扩容到了本地节点上…

前端初级html\css知识点总结

以前的笔记&#xff0c;初级前端知识点&#xff0c;浅显易懂&#xff0c; 一&#xff0c;htmlcss基础 1-1 Html和CSS的关系 学习web前端开发基础技术需要掌握&#xff1a;HTML、CSS、JavaScript语言。下面我们就来了解下这三门技术都是用来实现什么的&#xff1a; 1. HTML是网…

单片机备用电池供电电路_第五节(重排) 电子入门 复位电路

时间有限&#xff0c;无法一一修改底部目录&#xff0c;请以此目录为准&#xff1a;向导&#xff1a;总目录&#xff1a;最好的电子、计算机从入门到工程师教程​zhuanlan.zhihu.com很多看完第三节 电子入门后&#xff0c;感觉难度陡然升高&#xff0c;适应不了&#xff0c;有情…

jQuery插件开发全解析

http://www.iteye.com/topic/545971 jQuery插件的开发包括两种&#xff1a;一种是类级别的插件开发&#xff0c;即给jQuery添加新的全局函数&#xff0c;相当于给jQuery类本身添加方法。jQuery的全局函数就是属于jQuery命名空间的函数&#xff0c;另一种是对象级别的插件开发&a…

jsf 传参数_在JSF 2中对定制验证器进行参数化

jsf 传参数在JSF 2中编写自定义验证器并不是一项复杂的任务。 您实现Validator接口&#xff0c;添加FacesValidator批注&#xff0c;并在faces-config.xml中插入validator声明&#xff0c; 仅此而已 。 一块蛋糕。 但是&#xff0c;让我们考虑以下情形&#xff1a; 您需要自定义…

java应该怎么学习?

很多人刚接触java,比较迷茫,下面我简单梳理一下后端的框架,希望你们能对java有个清晰的认识。 java是一种纯面向对象的编程语言,也是三大编程语言之一。java是由sun公司于1995年开发,它被称为“一次编译,处处可用”。 Struts在项目中的作用 Struts 在项目主要起控制作用…

docker安装clickhouse_clickhouse ----入门

clickhouse作为现在流行的数据分析数据库&#xff0c;非常热门。我也眼馋了好久&#xff0c;想先本地单机安装下&#xff0c;网上搜索了好多。也遇到了好多问题。我这边讲述下自己安装的过程。我这边的电脑是mac.第一步是安装docker.执行命令 brew cask install docker。等dock…

树——平衡二叉树插入和查找的JAVA实现

package com.tomsnail.data.tree; /*** AVL二叉平衡树* author tomsnail* date 2015年3月30日 下午4:35:50*/ public class AVLTree {/*** 根节点* author tomsnail* date 2015年3月30日 下午4:36:54*/private AVLNode rootNode;private String bulidType "";/*** 增…

APP推广工具(总结)

全是干活,懂得人慢慢听我道来。 基于友盟+大数据,如有侵权请告知与我。 一、学习、资讯 1.渠道点评 网址:http://qddp.niaogebiji.com/ 简介:渠道点评是专注于广告、营销、推广商务合作渠道资源点评的综合平台,聚合App推广、信息流广告等众多主流推广渠道广告代理商公…

JUnit:使用Java 8和AssertJ 3.0.0测试异常

Java 8的AssertJ 3.0.0发行版比以前更容易测试异常。 在我以前的一篇博客文章中&#xff0c;我描述了如何利用纯 Java 8实现此目的&#xff0c;但是使用AssertJ 3.0.0可能会删除我创建的许多代码。 警告&#xff1a;此博客文章主要包含代码示例。 SUT –被测系统 我们将测试以…

怎么修改_论文查重之后怎么修改?

使用知网论文查重以后&#xff0c;发现论文重复率很高&#xff0c;该怎么办&#xff1f;论文查重后怎么改&#xff1f;今天paperfree小编给大家介绍一下。方法一&#xff1a;重写如果论文存在很高的重复率&#xff0c;都是抄袭别人的论文&#xff0c;我们就可以考虑重写。在重写…

java枚举使用详解

package com.ljq.test;/** * 枚举用法详解 * * author jiqinlin * */ public class TestEnum { /** * 普通枚举 * * author jiqinlin * */ public enum ColorEnum { red, green, yellow, blue; }/** * 枚举像普通的类一样可以添加属性和方法&#xff0c;可以为它添加静态和非静…

js数组再倒数第二个添加元素_归纳JS中数组的使用(一)元素新增和删除

新增元素js中给数组新增元素主要通过2个方法 push 和 unshiftArray.prototype.push功能概述push() 方法将一个或多个元素添加到数组的末尾&#xff0c;并返回该数组的新长度(该方法修改原有数组)。语法arr.push(element1, ..., elementN)关注点新增的元素出现在数组的末尾可以一…

基于谷歌模型gemini-pro 的开发的QT 对话项目

支持的功能&#xff0c;新建对话框&#xff0c;目前发现相关梯子不支持访问谷歌的api 的可能代理设置的不对&#xff0c; QNetworkAccessManager manager;// Set up your requestQNetworkRequest request;request.setUrl(QUrl("https://generativelanguage.googleapis.com…

PS快速将白底图片变为透明图片的解决办法

公司的公章被傻逼老板带到国外去啦&#xff0c;现在还得用公章&#xff0c;就只能拿以前的文件p图啦。 在将白底图片修改为透明图片时&#xff0c;我首先能想到的是简单的利用磁性套索工具选择图片&#xff08;非常细微的操作&#xff09;&#xff0c;但是一不小心就容易出错&a…

Lucene.net站内搜索—5、搜索引擎第一版实现

目录 Lucene.net站内搜索—1、SEO优化 Lucene.net站内搜索—2、Lucene.Net简介和分词 Lucene.net站内搜索—3、最简单搜索引擎代码Lucene.net站内搜索—4、搜索引擎第一版技术储备&#xff08;简单介绍Log4Net、生产者消费者模式&#xff09;Lucene.net站内搜索—5、搜索引擎第…

java ee jms_Java EE6事件:JMS的轻量级替代品

java ee jms我今天要讨论的功能是Java EE 6中的事件机制。一般的想法是触发一个事件&#xff0c;并让事件监听器来接收它。 我创建了这个完全没有用的示例&#xff0c;但是它的简单性帮助我专注于重要的内容。 我将从后备操作中触发LogEvent&#xff0c;该事件将记录到java.uti…

All your files have been encrypted

小弟的姑姑家的老板收银的电脑被黑客黑了,我来解决一下,小孩玩游戏玩电脑中的病毒, 方法很多种,仅供参考。 问题邮件截图: 参考方式: 方法一:给对方钱,一般比较贵,还不如重装系统。哈哈。 方法二:下载解密工具,尝试解密恢复数据, Ransomware File Decrypto Too…

8s yaml 配置生成_接口测试框架实战(六) | 配置的数据驱动

《Python 测试开发实战进阶》课程&#xff0c;4 个月挑战 BAT 大厂年薪 50W Offer&#xff0c;文末加群&#xff01;在实际工作中&#xff0c;为了便于维护&#xff0c;对于环境的切换和配置&#xff0c;通常不会使用硬编码的形式完成。在之前文章《多环境下的接口测试》中&…