Gleichwertiger Code für die Synchronisation von Instanzmethoden in Java

8

Bei der Erörterung einer Java-Synchronisierung question jemand hat bemerkt, dass die folgenden Snippets nicht äquivalent sind (und zu verschiedenen Bytecodes kompilieren können):

%Vor%

und

%Vor%

Sind sie gleichwertig?

    
eljenso 06.01.2009, 16:50
quelle

7 Antworten

13

Sie sind in ihrer Funktion äquivalent, obwohl die Compiler, die ich getestet habe (Java 1.6.0_07 und Eclipse 3.4), unterschiedliche Bytecodes erzeugen. Der erste generiert:

%Vor%

Die zweite erzeugt:

%Vor%

(Danke an ASM für den Bytecode-Druck).

Der Unterschied zwischen ihnen besteht also weiterhin auf der Bytecode-Ebene, und es liegt an der JVM, ihr Verhalten gleich zu machen. Sie haben jedoch den gleichen funktionalen Effekt - siehe Beispiel in der Java-Sprachspezifikation.

Es sollte beachtet werden, dass, wenn die Methode in einer Unterklasse außer Kraft gesetzt wird, sie nicht notwendigerweise synchronisiert ist - also gibt es auch keinen Unterschied in dieser Hinsicht.

Ich habe auch einen Test ausgeführt, um einen Thread zu blockieren, der in jedem Fall versucht, auf den Monitor zuzugreifen, um zu vergleichen, wie seine Stack-Traces in einem Thread-Dump aussehen würden, und beide enthalten die fragliche Methode.

    
Dave L. 06.01.2009, 17:14
quelle
7

Ich habe den ursprünglichen Kommentar gemacht, dass die Aussagen identisch sind.

In beiden Fällen ist das erste, was passiert, dass der aufrufende Thread versucht, den Monitor des aktuellen Objekts (dh this ') zu erfassen.

Ich weiß nicht über verschiedene Bytecode, ich bin glücklich, den Unterschied zu hören. Aber in der Praxis sind sie zu 100% identisch.

BEARBEITEN: Ich werde das klären, da einige Leute hier falsch lagen. Überlegen Sie:

%Vor%

In diesem Fall überschreibt doStuff() in Klasse B weiterhin doStuff() in Klasse A, obwohl es nicht synchronisiert ist.

Synchronisiertes Schlüsselwort ist niemals Teil des Vertrags! Nicht für Unterklassen, nicht für Schnittstellen, nicht für abstrakte Klassen.

    
Yuval Adam 06.01.2009 16:58
quelle
4

Ich habe den ursprünglichen Kommentar gemacht. Mein Kommentar war, dass sie logisch gleichwertig sind, aber zu verschiedenen Bytecode kompilieren.

Ich habe nichts hinzugefügt, um es zu dieser Zeit zu rechtfertigen, weil es nicht viel zu rechtfertigen gibt - sie tun nur zu einem anderen Bytecode. Wenn Sie eine Methode als synchronized deklarieren, ist diese Synchronisation Teil der Definition der Methode. Ein synchronisierter Block innerhalb einer Methode ist kein Teil der Methodendefinition , sondern beinhaltet separate Bytecodes zum Erfassen und Freigeben des Monitors, wie eines der obigen Poster gezeigt hat. Streng genommen sind das etwas unterschiedliche Dinge, obwohl für die Gesamtlogik Ihres Programms gleichwertig sind. . .

Wann ist das wichtig? Nun, auf den meisten modernen Desktop-VMs kaum. Aber zum Beispiel:

  • Eine VM könnte im Prinzip Optimierungen in einem Fall, aber nicht im anderen machen
  • es gibt einige JIT-Compiler-Optimierungen, bei denen die Anzahl von Bytecodes in der Methode als ein Kriterium dafür verwendet wird, welche Optimierungen vorgenommen werden sollen
  • ein VM ohne ein JIT-Compiler (zugegebenermaßen wenige heutzutage, aber vielleicht auf einem älteren mobilen Gerät?) wird mehr Bytecodes haben, die bei jedem Aufruf verarbeitet werden
Neil Coffey 06.01.2009 18:09
quelle
2

Ja. Wenn Sie das synchronisierte Schlüsselwort für eine Instanzmethode verwenden, wird 'this' als Monitor verwendet. Wenn Sie es für eine Klassenmethode verwenden (statische Methode), wird die Klasse 'Class object (Foo.class)' verwendet.

Auf diese Weise können Sie ganze Methoden synchronisieren und gleichzeitig mit einem Code-Snippet in einer anderen Methode synchronisieren, indem Sie den synchronisierten Blockstil verwenden.

    
abyx 06.01.2009 16:58
quelle
0

Ich kann keinen funktionalen Unterschied sehen - beide synchronisieren ihre gesamten Methodenkörper auf (this). Wie hat die Person, die diese Unterschiede erklärt hat, ihre Aussage gerechtfertigt?

    
Steve B. 06.01.2009 16:58
quelle
0

Sie sind in ihrer Funktion nicht ganz gleichwertig. Anderer Code könnte Reflektion verwenden, um zu sehen, ob Ihre Methode den synchronisierten Modifikator hat, aber es gibt keine Möglichkeit festzustellen, ob eine Methode einen synchronisierten Block enthält, ohne dessen Bytecode zu lesen.

Die Möglichkeit zu bestimmen, ob eine Methode gelegentlich synchronisiert wird, ist praktisch. Persönlich habe ich dieses Flag verwendet, um eine redundante Sperrung bei der Synchronisierung bei der aspektorientierten Programmierung zu vermeiden.

    
Andrew 20.04.2012 20:14
quelle
-1
%Vor%

In diesem Fall:

  • someMethod blockiert die gesamte Klasse
  • someMethodA blocks myObjectA only
  • someMethodB blocks myObjectB only
  • someMethodA und someMethodB können gleichzeitig aufgerufen werden
Guest 16.03.2009 09:23
quelle

Tags und Links