五、原子操作之DoubleAdder

1. 前言
今天为大家介绍原子操作之 DoubleAdder。此工具位于 java.util.concurrent.atomic 包中。

本节先介绍 DoubleAdder 工具类的基本概念和最基本用法,之后给出 DoubleAdder 工具类最常用的场合说明,然后通过简单的编码实现一个实际案例,让大家有一个理性的认识,最后带领大家熟悉 DoubleAdder 最常用的一些编程方法,进一步加深对 DoubleAdder 工具类的理解。

下面我们正式开始介绍吧。

2. 概念介绍
DoubleAdder 工具类采用了 “分头计算最后汇总” 的思路,避免每一次(细粒度)操作的并发控制,提高了并发的性能。什么是细粒度的同步控制呢?所谓细粒度的同步控制,指的是对待同步控制对象的每一次操作都需要加以控制,这样描述是不是有点抽象,别着急,看下面的图示。
在这里插入图片描述

我们看下面 DoubleAdder 工具类的基本用法。

3. 基本用法

// 首先创建一个 DoubleAdder 对象
DoubleAdder doubleAdder = new DoubleAdder();
...
// 调用累加方法
doubleAdder.add(50.5);
doubleAdder.add(49.5);
// 调用求和方法
double sum = doubleAdder.sum();
...

是不是很简单,那 DoubleAdder 在我们日常实践中,到底应该应用在哪些场合比较合适呢?下面我们给出最常用的场景说明。

4. 常用场景
DoubleAdder 经常用于多线程并发做收集统计数据的场合,而不是细粒度的同步控制。
下面我们用 DoubleAdder 工具类实现一个生活案例:某商场为了掌握客流特征,在商场所有出入口架设了人体特征识别设备,此类设备可以有效识别客人性别等信息。基于此,商场管理办公室计划制作一个客流性别流量图表,用于决策商场的服务内容。

5. 场景案例

import java.util.concurrent.atomic.DoubleAdder;

public class DoubleAdderTest {

    // 首先创建三个 DoubleAdder 对象分别表示统计结果
    // 代表当天所有进入商场的男性客户总数量
    private static DoubleAdder maleCount = new DoubleAdder();
    // 代表当天所有进入商场的女性客户总数量
    private static DoubleAdder womenCount = new DoubleAdder();
    // 代表当天所有进入商场的未能识别的客户总数量
    private static DoubleAdder unknownGenderCount = new DoubleAdder();

    public static void main(String[] args) {
        // 定义30个商场入口检测设备
        for (int i = 1; i <= 30; i++) {
            MonitoringDevice monitoringDevice = new MonitoringDevice(maleCount, womenCount, unknownGenderCount, i);
            // 开启检测设备进行检测
            new Thread(monitoringDevice).start();
        }
    }
}

在上面的代码中,首先创建三个 DoubleAdder 对象分别表示统计结果,然后创建了 30 个商场入口检测设备模拟检测识别,接下来每个检测设备如何动作呢,看下面的代码。

import java.util.Random;
import java.util.concurrent.atomic.DoubleAdder;

public class MonitoringDevice implements Runnable {

    private DoubleAdder maleCount;
    private DoubleAdder womenCount;
    private DoubleAdder unknownGenderCount;

    private String monitoringDeviceNo;

    public MonitoringDevice(DoubleAdder maleCount, DoubleAdder womenCount, DoubleAdder unknownGenderCount, int monitoringDeviceNo) {
        this.maleCount = maleCount;
        this.womenCount = womenCount;
        this.unknownGenderCount = unknownGenderCount;
        this.monitoringDeviceNo = "第" + monitoringDeviceNo + "监控采集处";
    }

    public void run() {
        while (true) {
            // 监测处理 (监测设备输出1代表男性,0代表女性,其他代表未能识别,此处随机产生监测结果)
            try {
                Thread.sleep(new Random().nextInt(3000));
            } catch (Exception e) {}
            int monitoringDeviceOutput = new Random().nextInt(3);

            // 对监测结果进行统计
            switch (monitoringDeviceOutput) {
                case 0: womenCount.add(1); 
                    System.out.println("统计结果: womenCount=" + womenCount.sum());
                    break;
                case 1: maleCount.add(1); 
                    System.out.println("统计结果: maleCount=" + maleCount.sum());
                    break;
                default: unknownGenderCount.add(1);
                    System.out.println("统计结果: unknownGenderCount=" + unknownGenderCount.sum());
                    break;
            }
        }
    }
}

MonitoringDevice 类中,首先模拟监测设备输出,然后将输出结果使用 add () 进行统计累加,使用 sum () 输出累加结果。运行一段时间后运行结果如下。

...
统计结果: unknownGenderCount=23.0
统计结果: womenCount=24.0
统计结果: maleCount=32.0
...

上面的案例中,总共计算了三个统计值,每一个统计值都使用了多个线程同时进行统计计算。在统计过程中,每一个线程只需要累加自己的那份统计结果,所以不需要做同步控制,只要在最后进行汇总统计结果时做同步控制进行汇总即可。像这样的场景使用 DoubleAdder 工具类会非常方便简洁。

至此,大家对 DoubleAdder 已经有了初步的理解,接下来我们继续丰富对 DoubleAdder 工具类的认识。

6. 核心方法介绍
除过上面代码中使用的最基本的 add (int)、sum () 方法之外,我们再介绍两个方法的使用。

  • reset () 方法

将累加器值置为 0,即为后继使用重新归位。

  • sumThenReset () 方法

此方法逻辑等同于先调用 sum () 方法再调用 reset () 方法,简化代码编写。

7. 小结
本节通过一个简单的例子,介绍了 DoubleAdder 的基本用法。在 java.util.concurrent.atomic 包中还有一个类似的工具类 LongAdder,用法大同小异,希望大家在日常研发中多比较多总结,早日掌握之。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jysf98746

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值