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

首頁 慕課教程 Java并發工具 Java并發工具 原子操作之LongAccumulator

原子操作之 LongAccumulator

1. 前言

今天為大家介紹原子操作之 LongAccumulator。此工具位于 java.util.concurrent.atomic 包中。

本節先介紹 LongAccumulator 工具類的基本概念和最基本用法,之后給出 LongAccumulator 工具類最常用的場合說明,然后通過簡單的編碼實現一個實際案例,最后帶領大家熟悉 LongAccumulator 最常用的一些編程方法,讓大家進一步加深對 LongAccumulator 工具類的理解。

下面我們正式開始介紹吧。

2. 概念介紹

相比 LongAdder,LongAccumulator 工具類提供了更靈活更強大的功能。不但可以指定計算結果的初始值,相比 LongAdder 只能對數值進行加減運算,LongAccumulator 還能自定義計算規則,比如做乘法運行,或其他任何你想要的計算規則。這樣描述是不是有點抽象,別著急,看下面的圖示。
圖片描述
我們看下面 LongAccumulator 工具類的基本用法。

3. 基本用法


// 首先創建一個雙目運算器對象,這個對象實現了計算規則。
LongBinaryOperator longBinaryOperator = new LongBinaryOperator() {
        @Override
        public long applyAsLong(long left, long right) {
            ...
        }
    }

// 接著使用構造方法創建一個 LongAccumulator 對象,這個對象的第1個參數就是一個雙目運算器對象,第二個參數是累加器的初始值。
LongAccumulator longAccumulator = new LongAccumulator(longBinaryOperator, 0);
...
// 調用累加方法
longAccumulator.accumulate(1000)
// 調用結果獲取方法
long result = longAccumulator.get();
...

是不是簡單又強大!LongAccumulator 在我們日常實踐中,到底應該應用在哪些場合比較合適呢?下面我們給出最常用的場景說明。

4. 常用場景

LongAccumulator 經常用于自定義運算規則場景下的多線程并發場合。一些簡單的累加計算可以直接使用我們之前課程中介紹的工具類,但是當運行規則比較復雜或者 JDK 沒有提供對應的工具類時,可以考慮 LongAccumulator 輔助實現。當然所有可使用 LongAdder 的場合都可使用 LongAccumulator 代替,但是沒有必要。

下面我們用 LongAccumulator 工具類實現上一節中的生活實例,為了簡化敘述,本節我們只統計男性客戶總數量。請看下面的代碼。

5. 場景案例

import java.util.concurrent.atomic.LongAccumulator;

public class LongAccumulatorTest {

	// 此處的運算規則是累加,所以創建一個加法雙目運算器對象作為構造函數的第一個參數。
    // 將第二個參數置為0,表示累加初始值。
    // maleCount 對象代表當天所有進入商場的男性客戶總數量。
    private static LongAccumulator maleCount = new LongAccumulator(new LongBinaryOperator() {
	    // 此方法用于實現計算規則
        @Override
        public long applyAsLong(long left, long right) {
	        // 在本例中使用加法計算規則
            return left + right;
        }
    }, 0);

    public static void main(String[] args) {
        // 定義30個商場入口檢測設備
        for (int i = 1; i <= 30; i++) {
            MonitoringDevice monitoringDevice = new MonitoringDevice(maleCount, i);
            // 開啟檢測設備進行檢測
            new Thread(monitoringDevice).start();
        }
    }
}

在上面的代碼中,首先創建一個 LongAccumulator 對象表示統計結果,然后創建了 30 個商場入口檢測設備模擬檢測識別,接下來每個檢測設備如何動作呢,看下面的代碼。

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

/**
 * 模擬設備
 */
public class MonitoringDevice implements Runnable {
    private LongAccumulator maleCount;
    private String monitoringDeviceNo;
    public MonitoringDevice(LongAccumulator maleCount, int monitoringDeviceNo) {
        this.maleCount = maleCount;
        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 1: maleCount.accumulate(1);
                    System.out.println("統計結果: maleCount=" + maleCount.get());
                    break;
                default:
                    System.out.println("忽略統計");
                    break;
            }
        }
    }
}

在 MonitoringDevice 類中,首先模擬監測設備輸出,然后將輸出結果使用 add () 進行統計累加,使用 sum () 輸出累加結果。運行一段時間后運行結果如下。

...
忽略統計
統計結果: maleCount=50
...

上面的示例中,使用 LongAccumulator 實現了上一節中相同的需求。對比觀察,能夠體會到 LongAccumulator 工具類更靈活的地方,但同時也更復雜一些。

至此,大家對 LongAccumulator 已經有了初步的理解,接下來我們繼續豐富對 LongAccumulator 工具類的認識。

6. 核心方法介紹

除過上面代碼中使用的最基本的 accumulate (int)、get () 方法之外,我們再介紹兩個方法的使用。

  1. reset () 方法

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

  1. getThenReset () 方法

此方法邏輯等同于先調用 get () 方法再調用 reset () 方法。

7. 小結

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