Warum ist `synchronisiert (neues Objekt ()) {}` ein No-Op?

Im folgenden Code:

class A {
    private int number;

    public void a() {
        number = 5;
    }

    public void b() {
        while(number == 0) {
            // ...
        }
    }
}

Wenn Methode b aufgerufen wird und dann ein neuer Thread gestartet wird, der Methode a auslöst, ist nicht garantiert, dass Methode b jemals die Änderung von @ siehnumber und somitb kann niemals enden.

atürlich könnten wir @ machnumber volatile, um dies zu beheben. Nehmen wir jedoch aus akademischen Gründen an, dassvolatile ist keine Option:

Das JSR-133 FAQs sagt uns

Nach dem Verlassen eines synchronisierten Blocks geben wir den Monitor frei, der hat den Effekt, dass der Cache in den Hauptspeicher geleert wird, damit die von diesem Thread erstellten Schreibvorgänge für andere Threads sichtbar sind. Bevor wir einen synchronisierten Block eingeben können, erfassen wir den Monitor, der hat den Effekt, dass der Cache des lokalen Prozessors ungültig wird, damit die Variablen aus dem Hauptspeicher neu geladen werden.

Das klingt wie ich brauche nur beidea undb um ein beliebiges @ zu betreten und zu verlasssynchronized -Block überhaupt, egal welchen Monitor sie benutzen. Genauer klingt es so ...:

class A {
    private int number;

    public void a() {
        number = 5;
        synchronized(new Object()) {}
    }

    public void b() {
        while(number == 0) {
            // ...
            synchronized(new Object()) {}
        }
    }
}

... würde das Problem beseitigen und garantiert, dassb wird die Änderung in @ seha und damit wird auch irgendwann kündigen.

Die FAQs enthalten jedoch auch folgende Informationen:

Eine weitere Implikation ist, dass das folgende Muster, das einige Leute verwenden, um eine Speicherbarriere zu erzwingen, nicht funktioniert:

synchronized (new Object()) {}

Dies ist eigentlich ein No-Op, und Ihr Compiler kann es vollständig entfernen, da der Compiler weiß, dass kein anderer Thread auf demselben Monitor synchronisiert. Sie müssen eine Beziehung vor dem Eintreten einrichten, damit ein Thread die Ergebnisse eines anderen Threads anzeigt.

Now das ist verwirrend. Ich dachte, dass die synchronisierte Anweisung Caches zum Leeren bringt. Ein Cache kann sicherlich nicht so in den Hauptspeicher entleert werden, dass die Änderungen im Hauptspeicher nur von Threads gesehen werden können, die auf demselben Monitor synchronisiert werden, zumal für Volatile, die im Grunde dasselbe tun, wir nicht einmal einen benötigen überwachen, oder irre ich mich dort? Also, warum ist dies ein No-Op und verursacht nichtb durch Garantie kündigen?

Antworten auf die Frage(4)

Ihre Antwort auf die Frage