10 Stimmen

Entfernt/optimiert Java unnötige synchronisierte Anweisungen?

Nehmen wir an, jemand synchronisiert eine Methode, die ein int zurückgibt:

int whatever = 33;
...

public synchronized int getWathever() {
    return this.whatever;
}

Aus den Java-Spezifikationen wissen wir, dass Ints atomar verändert werden. Daher ist die synchronized Anweisung ist nicht erforderlich.

Werden die Compiler sie entfernen/optimieren?

7voto

ratchet freak Punkte 45968

Synchronized hat neben dem Erhalt einer Sperre noch weitere Auswirkungen auf die Threadsicherheit (z.B. ist sichergestellt, dass die geänderten Daten für andere Threads sichtbar sind)

Solange diese Nebeneffekte gültig sind, kann die JIT im Wesentlichen tun, was sie will.

im Beispiel muss jedoch sichergestellt werden, dass die Sperre während des Ladens der Variablen nicht von einem anderen Thread gehalten wird, was am einfachsten durch die effektive Erlangung der Sperre zu gewährleisten ist

7voto

Vineet Reynolds Punkte 74302

Nein, das ist einfach nicht möglich. Wenn der Compiler und die JVM dies tun würden, ist es wahrscheinlich, dass die Einschränkungen, die durch die Speichermodell der Programmiersprache Java verletzt werden würde.

Genauer gesagt, die _Synchronisationsauftrag_ Die in der Java-Sprachenspezifikation festgelegte Reihenfolge würde verletzt. Wenn ein Compiler oder eine JVM * alle "unerwünschten" Synchronisationen entfernen würde, dann würden alle weiteren Optimierungen gegen die Annahmen verstoßen, die ein Entwickler in Bezug auf die Synchronisationsreihenfolge (und die "happens-before"-Beziehung) gemacht hat. In Ihrem speziellen Fall wird in einem Compiler/JVM, der sich an das Java-Speichermodell hält, jedes Schreiben auf die Ganzzahl vor dem Lesen erfolgen.

Ein Compiler/JVM, der die Synchronisationen entfernt, würde lediglich zu einer Umgebung führen, in der das Speichermodell verletzt wird. Beispielsweise könnte das Inlining von Methoden durchgeführt werden, ohne dass der Compiler/die JVM eine Speichersperre vor dem Lesen des Integer-Wertes setzt, wodurch veraltete Werte aus einem Cache-Wert gelesen werden könnten.

* Der Verweis auf das Compiler/JVM-Duo ist beabsichtigt. Ein Compiler wird nur Bytecode ausgeben, der mit der JLS konform ist; eine JVM könnte einfach einen Fehler haben, bei dem die Anforderungen des Speichermodells trotzdem verletzt werden könnten. Im Interesse der Vollständigkeit des Speichermodells sollten sowohl der Compiler als auch die JVM die Anforderungen des Speichermodells erfüllen.

5voto

irreputable Punkte 43667

Es gibt Fälle, in denen VM eine Sperre beseitigen kann. Zum Beispiel

Fluchtanalyse

int bar()
    Foo foo = new Foo();
    return foo.getWhatever();

VM kann folgern, dass foo für keinen anderen Thread sichtbar ist, daher wird niemand versuchen, es zu sperren, daher wird das Sperren der getWhatever Methode kann entfallen.

Sperre Vergröberung

Foo foo = ...;
void bar()
    a();
    foo.getWhatever();
    b();
    foo.getWhatever();
    c();

rechtmäßig zusammengelegt werden können, um eine Schließung zu vermeiden

void bar()
    synchronized(foo)
        a();
        foo.getWhatever_without_lock();
        b();
        foo.getWhatever_without_lock();
        c();

Eine weitere gute Nachricht ist, dass die gesperrte Region aufgrund des adaptiven Lockings so kurz ist, dass VM höchstwahrscheinlich Spin Lock dafür verwenden wird; eine Threadunterbrechung aufgrund eines fehlgeschlagenen Lockings ist sehr unwahrscheinlich.

4voto

Ryan Stewart Punkte 120600

Es ist absolut nicht sicher, dass "synchronisiert" zu entfernen, wenn die Absicht ist, es Thread-sicher zu machen, es sei denn, Sie sicherstellen, dass die int-Variable ordnungsgemäß mit dem Hauptspeicher in irgendeiner anderen Weise synchronisiert ist, so dass in diesem Fall, nein.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X