亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

原子操作之 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 工具類實現一個生活案例:某商場為了掌握客流特征,在商場所有出入口架設了人體特征識別設備,此類設備可以有效識別客人性別等信息?;诖耍虉龉芾磙k公室計劃制作一個客流性別流量圖表,用于決策商場的服務內容。

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 () 方法之外,我們再介紹兩個方法的使用。

  1. reset () 方法

將累加器值置為 0,即為后繼使用重新歸位。

  1. sumThenReset () 方法

此方法邏輯等同于先調用 sum () 方法再調用 reset () 方法,簡化代碼編寫。

7. 小結

本節通過一個簡單的例子,介紹了 DoubleAdder 的基本用法。在 java.util.concurrent.atomic 包中還有一個類似的工具類 LongAdder,用法大同小異,希望大家在日常研發中多比較多總結,早日掌握之。