Verhalten der memory-Barriere in Java

Nach dem Lesen mehr blogs/Artikel etc, ich bin jetzt wirklich verwirrt über das Verhalten von load/store-vor - /nach-memory-Barriere.

Folgenden 2 Zitate von Doug Lea in einem seiner Klarstellung Artikel über JMM, die sind beide sehr unkompliziert:

  1. Alles, was sichtbar war, zu thread A, wenn er schreibt, um flüchtige Feld f wird sichtbar, thread B, wenn es liest f.
  2. Beachten Sie, dass es wichtig ist, für beide threads auf dieselbe volatile-variable, um richtig einrichten des happens-before-Beziehung. Es ist nicht so, dass alles sichtbar thread Ein, wenn es schreibt flüchtigen Feld f wird sichtbar, thread B nach der es liest flüchtig Feld g.

Aber dann, als schaute ich in eine andere blog über die memory-Barriere, habe ich diese:

  1. Einer store-barrier, "sfence" - Befehl auf x86 -, zwingt alle store-Anweisungen vor, um die Barriere zu passieren, bevor die Barriere und haben die store-buffer geleert-cache für die CPU, auf die Sie ausgestellt wird.
  2. Eine Last barrier, "lfence" - Befehl auf x86 -, erzwingt Sie, dass alle load-Anweisungen nachdem die Barriere zu passieren, nach der Schranke und warten dann auf die load-Puffer zu entleeren für die CPU.

Mir, Doug Lea ' s Klarstellung ist strenger als die andere: im Grunde bedeutet es, wenn der laden Barriere-und store-barrier werden auf verschiedenen Monitoren, kann die Konsistenz der Daten nicht gewährleistet werden. Aber später bedeutet, selbst wenn die Barrieren auf verschiedenen Monitoren, kann die Konsistenz der Daten gewährleistet werden. Ich bin nicht sicher, ob ich das Verständnis dieser 2 richtig und auch ich bin mir nicht sicher, welche von Ihnen richtig ist.

Unter Berücksichtigung der folgenden codes:

  public class MemoryBarrier {
    volatile int i = 1, j = 2;
    int x;

    public void write() {
      x = 14; //W01
      i = 3;  //W02
    }

    public void read1() {
      if (i == 3) {  //R11
        if (x == 14) //R12
          System.out.println("Foo");
        else
          System.out.println("Bar");
      }
    }

    public void read2() {
      if (j == 2) {  //R21
        if (x == 14) //R22
          System.out.println("Foo");
        else
          System.out.println("Bar");
      }
    }
  }

Sagen wir, wir haben 1 schreiben thread TW1 ersten Aufruf der MemoryBarrier die write () - Methode, dann haben wir 2 Leser-threads TR1 und TR2 nennen MemoryBarrier ist read1() und read2 () - Methode.Betrachten Sie dieses Programm ausführen auf der CPU, die nicht erhalten Bestellung (x86 beibehalten der Bestellung für solche Fälle was nicht der Fall ist), je nach Speicher-Modell, wird es eine StoreStore Barriere (sagen wir SB1) zwischen W01/W02, sowie 2 LoadLoad Barriere zwischen R11/R12 und R21/R22 (sagen wir mal, RB1 und RB2).

  1. Seit SB1 und RB1 sind am gleichen monitor ich, also thread TR1, welche Anrufe read1 sollte immer sehen, 14 x, auch "Foo" wird immer gedruckt.
  2. SB1 und RB2 sind auf verschiedenen Monitoren, wenn Doug Lea ist richtig, thread TR2 werden nicht garantiert, um zu sehen, 14 x, was bedeutet, "Bar" gedruckt werden kann gelegentlich. Aber wenn die memory-Barriere läuft wie Martin Thompson beschrieben in der blog, den laden Sperre schieben Sie alle Daten im Hauptspeicher und Last-Schranke ziehen alle Daten vom Hauptspeicher zum cache/Puffer, dann TR2 wird auch garantiert werden, um zu sehen, 14 auf x.

Ich bin mir nicht sicher, welches der richtige ist, oder beide von Ihnen, aber was Martin Thompson beschrieben, ist nur für die x86-Architektur. JMM übernimmt keine Garantie änderung x der sichtbar ist, TR2, aber x86-Implementierung unterstützt.

Dank~

  • Man sollte sich keine Gedanken über die memory-Barrieren auf x86. Die Semantik von Java und das Java-Memory-Modell definiert sind, auf eine abstrakte Maschine. Das ist das einzige, was zählt. Die Java-Laufzeitumgebung sorgt dafür, dass die Garantien durch die abstrakte Maschine erfüllt sind, während der Laufzeit.
  • Als eine Angelegenheit von der Tat die x86-Semantik (einschließlich der cache-Kohärenz) sind stärker als das, was die jmm Anforderungen, aber es gibt keinen Grund für Sie interessiert, wenn Sie nicht arbeiten auf einer java-Laufzeitumgebung für x86 als nosid richtig Punkte raus.
  • Ihr Anliegen ist gültig. Es ist möglich // die reader-2 Bar Druck. Jedoch, wenn der Leser threads hatte vorher in Wechselwirkung mit der memory-Barriere-Klasse zwischengespeichert und der Wert von x, reader 2 print foo, weil es auf x für die erste Zeit. Die Interaktion mit schreiben bedeutet die änderung für x sichtbar. Vielleicht ein interessanter test ist read1 und read2 führen sowohl vor und nach W1.
  • CountDownLatch führt eine weitere Synchronisierung. Also, wenn Sie CountDownLatch sicher zu stellen, dass read2 ausgeführt wird, nachdem write, dann read2 immer drucken "Foo".
  • Die Antwort ist: "Bar" ist natürlich möglich, wenn es keine Synchronisation zwischen write und read2, und es ist nicht möglich, wenn es eine Synchronisation. Ich denke, das ist nicht das, was Sie interessiert. Also, bitte mehr Informationen liefern, was Sie wirklich wissen wollen.
  • Was Martin Thompson beschrieben in dem blog sind etwas anders mit Doug Lea ' s Klärung sowie JMM passiert-grundsätzlich vor, die ich ein wenig verwirrt bin. Ich denke, es ist nur für x86-Implementierung, nicht eine JMM Sache. BTW. sehr gute Fänge an CountDownLatch.
  • Ich glaube nicht, dass sfence leert die Speicher-Puffer-cache zu. Peterson/Decker Synchronisation muss mfence.

InformationsquelleAutor asticx | 2014-06-28
Schreibe einen Kommentar