Warum nimmt der JDK-Quellcode eine "endgültige" Kopie von "flüchtigen" Instanzen?

74

Ich habe den Quellcode des JDK über ConcurrentHashMap gelesen.

Aber der folgende Code hat mich verwirrt:

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

Meine Frage ist:

"this.segments" wird deklariert:

final Segment<K,V>[] segments;

Zeigen Sie hier zu Beginn der Methode, die dieselbe Typreferenz deklariert hat, auf denselben Speicher.

Warum hat der Autor es so geschrieben? Warum haben sie this.segments nicht direkt verwendet? Gibt es einen Grund?

HUA Di.
quelle

Antworten:

94

Dies ist eine Redewendung, die typisch für sperrfreien Code mit volatileVariablen ist. In der ersten Zeile lesen Sie das volatileeinmal und arbeiten dann damit. In der Zwischenzeit kann ein anderer Thread das aktualisieren volatile, aber Sie interessieren sich nur für den Wert, den Sie ursprünglich gelesen haben.

Auch wenn die betreffende Mitgliedsvariable nicht flüchtig, sondern endgültig ist, hat diese Redewendung mit CPU-Caches zu tun, da das Lesen von einem Stapelspeicherort cachefreundlicher ist als das Lesen von einem zufälligen Heapspeicherort. Es besteht auch eine höhere Wahrscheinlichkeit, dass die lokale Variable an ein CPU-Register gebunden wird.

Für diesen letzteren Fall gibt es tatsächlich einige Kontroversen, da sich der JIT-Compiler normalerweise um diese Bedenken kümmert, aber Doug Lea ist einer der Leute, die sich grundsätzlich daran halten.

Marko Topolnik
quelle
Wenn also jemand den this.segmentsInhalt ändert , sehen Sie diese Änderung nicht in Ihrem segments?
Brimborium
Natürlich wirst du es sehen. Aber wenn jemand etwas anderes zuweist segments, werden Sie offensichtlich davon isoliert sein.
Marko Topolnik
3
Ah ja sicher. Missverstand Ihre Antwort ...;)
Brimborium
Wenn Segmente (die Instanzvariable) als endgültig deklariert werden, kann sie sich nicht ändern. Ich erinnere mich, dass das Hinzufügen einer Superfluos-Loval-Variablen zum doppelt überprüften Idiom die Ausführung in einigen VMs beschleunigen könnte. Vielleicht ist dies ein ähnlicher Fall. (@ Marko hat das bereits mit einer ausführlicheren Erklärung hinzugefügt, danke!)
Pyranja
6
Wenn eine Variable isoliert von allem anderen gelesen wird, kann die Beschleunigung zwar erheblich sein, aber selbst die Leistung der Lesevorgänge im ungünstigsten Fall wird normalerweise von allen anderen Aspekten des Codes übertönt. Aus diesem Grund ist es sehr unwahrscheinlich, dass Sie in einer realen Anwendung jemals den Unterschied bemerken.
Marko Topolnik
19

Ich denke, es ist aus Gründen der Leistung, so dass wir den Feldwert nur einmal abrufen müssen.

Sie können sich auf eine Singleton-Sprache aus dem effektiven Java von Joshua Bloch beziehen

Sein Singleton ist hier:

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

und er schrieb:

Dieser Code kann etwas verworren erscheinen. Insbesondere kann die Notwendigkeit des Ergebnisses der lokalen Variablen unklar sein. Diese Variable stellt sicher, dass das Feld in dem allgemeinen Fall, in dem es bereits initialisiert wurde, nur einmal gelesen wird. Dies ist zwar nicht unbedingt erforderlich, kann jedoch die Leistung verbessern und ist nach den Standards für die gleichzeitige Programmierung auf niedriger Ebene eleganter. Auf meinem Computer ist die oben beschriebene Methode etwa 25 Prozent schneller als die offensichtliche Version ohne lokale Variable .

larry.li
quelle
4

Dies kann die Größe des Bytecodes verringern. Der Zugriff auf eine lokale Variable ist im Bytecode kürzer als der Zugriff auf eine Instanzvariable.

Der Aufwand für die Laufzeitoptimierung kann ebenfalls reduziert werden.

Aber keines davon ist von Bedeutung. Es geht mehr um den Codestil. Wenn Sie sich mit Instanzvariablen auf jeden Fall wohl fühlen. Doug Lea fühlt sich wahrscheinlich wohler im Umgang mit lokalen Variablen.

unwiderlegbar
quelle