74

ConcurrentHashMap に関する JDK のソース コードを読みました。

しかし、次のコードは私を混乱させました:

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

私の質問は:

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

final Segment<K,V>[] segments;

したがって、ここでは、メソッドの先頭で、同じ型参照を宣言し、同じメモリを指します。

著者はなぜこのように書いたのでしょうか。this.segments を直接使用しなかったのはなぜですか? 何か理由はありますか?

4

3 に答える 3

94

volatileこれは、変数を含むロックフリーコードに典型的なイディオムです。最初の行で、一度読んでvolatileからそれを操作します。その間、別のスレッドがを更新できvolatileますが、最初に読み取った値にのみ関心があります。

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

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

于 2012-10-31T10:31:57.000 に答える
19

パフォーマンスを考慮して、フィールド値を一度だけ取得する必要があると思います。

Joshua Bloch による effective java のシングルトン イディオムを参照できます。

彼のシングルトンはここにあります:

private volatile FieldType field;
FieldType getField() {
  FieldType result = field;
  if (result == null) { 
    synchronized(this) {
      result = field;
      if (result == null) 
        field = result = computeFieldValue();
    }
  }
  return result;
}

そして彼は書いた:

このコードは少し複雑に見えるかもしれません。特に、ローカル変数の結果の必要性が不明な場合があります。この変数が行うことは、フィールドが既に初期化されている一般的なケースで一度だけ読み取られるようにすることです。厳密には必要ではありませんが、これによりパフォーマンスが向上する可能性があり、低レベルの並行プログラミングに適用される標準により洗練されています。私のマシンでは、上記の方法は、ローカル変数を使用しない明らかなバージョンよりも約 25% 高速です

于 2012-10-31T10:52:24.890 に答える
4

バイトコードのサイズを減らすことができます - ローカル変数へのアクセスは、インスタンス変数へのアクセスよりもバイトコードで短くなります。

ランタイム最適化のオーバーヘッドも削減される可能性があります。

しかし、これらのどれも重要ではありません。それはコードスタイルに関するものです。インスタンス変数に慣れている場合は、ぜひ。Doug Lea はおそらく、ローカル変数をより快適に扱うことができると感じています。

于 2012-10-31T16:41:55.140 に答える