ホームページ >Java >&#&チュートリアル >Java 並行プログラミングの LongAdder ソース コード分析

Java 並行プログラミングの LongAdder ソース コード分析

PHPz
PHPz転載
2023-05-28 08:22:171389ブラウズ

はじめに

ソースコードに基づいて、その基本的な実装プロセスを分析してみましょう。

複数のスレッドが、きめ細かい同期制御ではなく、統計収集などの目的で使用される共通の合計を更新する場合、通常、このクラスは AtomicLong よりも推奨されます。ただし、競合が多い場合、スペース消費量が増える代わりに、このクラスの予想スループットは大幅に高くなります。

上記の段落は、LongAdder ソース コード コメントからのものです。その一部を大まかに翻訳すると、

このクラスは、複数のスレッドが統計の収集には使用されるが、きめ細かい同期制御を目的としていない共通の合計を更新する場合、一般に AtomicLong よりも優先されます。 。更新競合が少ない場合、これら 2 つのクラスは同様の特性を持ちます。ただし、競合が多い状況では、このクラスの予想スループットは大幅に高くなりますが、スペース消費量が増加します。

つまり、LongAdder は同時実行性が高い場合に効率的ですが、その代償としてスペースと時間のトレードオフが発生します。

LongAdder の原理を簡単に説明しましょう。同時実行性がほとんどない場合は、1 つの変数 base に対して累算演算を実行するだけで十分です。 AtomicLong も同様ですが、同時実行性が増加した場合、変数 base を引き続き操作すると、多くのスレッドがブロックされるため、配列 cells を作成します。 in 配列の各要素は累積できます。最終結果を計算するときは、basecells 配列の各要素の合計を計算するだけです。スレッドが動作する配列内の特定のビットは、hash を計算してインデックス位置を決定することで決定できます。

ソース コードの紹介

LongAdder親クラス Striped64 から継承された属性。ここでは Cell が内部クラスに使用されます。累積操作の には、累積値を格納するための内部 value 属性があります。

// CPU核心数
static final int NCPU = Runtime.getRuntime().availableProcessors();
// 并发高时进行累加的Cell数组
transient volatile Cell[] cells;
// 多个线程没有竞争时在base上进行累加
transient volatile long base;
// Cell数组是否正在创建或扩容
transient volatile int cellsBusy;

累積演算メソッドincrement()実際の呼び出しはadd(1L)なので、addメソッド##を直接見てみましょう。 #

public void add(long x) {
    Cell[] as; long b, v; int m; Cell a;
    if ((as = cells) != null || !casBase(b = base, b + x)) {
        boolean uncontended = true; // 表示没有竞争
        if (as == null || (m = as.length - 1) < 0 ||
            (a = as[getProbe() & m]) == null ||
            !(uncontended = a.cas(v = a.value, v + x)))
            longAccumulate(x, null, uncontended);
    }
}

まず、最初の

if ステートメントを見てみましょう。初期条件では、cellsnull であるため、casBase 操作はつまり、base 変数に対して累積が実行され、操作が成功した場合は、現在競合がいないことを意味するため、終了します。

同時実行数が多くなると、

casBaseメソッドが失敗する可能性があるため、この時点で2回目のif文の判定が入ります。

  • 初めて入ったとき、

    Cell arrayasnull であるため、 ##、Cell 配列 as を初期化し、インデックス 11 を累積します。

  • この
  • if

    ステートメント as を実行すると、null にはならず、配列の長さも 0 より大きくなります。

  • a = as[getProbe() & m]) == null

    、この文を簡単に理解すると、配列 as 位置、位置の値が null であるかどうかを判断し、null である場合は longAccumulate を実行し、## でない場合は longAccumulate を実行します。 #null、判断を続けます

  • !(uncontended = a.cas(v = a.value, v x))この文は、累積見つかったインデックス位置で操作が実行され、成功した場合は操作が終了し、失敗した場合は longAccumulate

  • が実行されます。

以上がJava 並行プログラミングの LongAdder ソース コード分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。