1. ホーム
  2. java

なぜ JDK ソースコードは `volatile` インスタンスの `final` コピーを取得するのか

2023-11-13 13:49:28

疑問点

JDKのソースコードで、ConcurrentHashMapについて読みました。

しかし、以下のコードで混乱しました。

public boolean isEmpty() {
    final Segment<K,V>[] segments = this.segments;
    ...
}

私の疑問は

"this.segments"が宣言されています。

final Segment<K,V>[] segments;

つまり、ここでは、メソッドの冒頭で、同じ型の参照を宣言し、同じメモリを指すようにしました。

作者はなぜこのような書き方をしたのでしょうか?なぜthis.segmentsを直接使わなかったのでしょうか?何か理由があるのでしょうか?

どのように解決するのか?

これは、ロックフリーのコードによくあるイディオムで、次のようなものがあります。 volatile 変数を含むロックフリーのコードによく見られるイディオムです。最初の行で、あなたは volatile を一度読み、それからそれを使って作業をします。その間に別のスレッドが volatile を更新することができますが、あなたは最初に読んだ値にしか興味がありません。

また、問題のメンバ変数が volatile ではなく final である場合でも、このイディオムは CPU キャッシュと関係があり、スタックロケーションから読み込む方がランダムなヒープロケーションから読み込むよりもキャッシュに優しいからです。また、ローカル変数が CPU レジスタにバインドされて終了する可能性も高くなります。

この後者の場合、JIT コンパイラは通常それらの懸念に対処するので、実際にはいくつかの論争がありますが、Doug Lea は一般的な原則でそれに固執する人の 1 人です。