Wenn ich zwei synchronisierte Methoden in derselben Klasse habe, aber jeweils auf unterschiedliche Variablen zugreift, können 2 Threads gleichzeitig auf diese beiden Methoden zugreifen? Tritt die Sperre für das Objekt auf oder wird sie so spezifisch wie die Variablen innerhalb der synchronisierten Methode?
Beispiel:
class X {
private int a;
private int b;
public synchronized void addA(){
a++;
}
public synchronized void addB(){
b++;
}
}
Kann 2 Threads greifen auf dieselbe Instanz der Klasse X Durchführung x.addA(
) und x.addB()
zur gleichen Zeit?
quelle
synchronized (this)
Block um den Hauptteil der Methode. Das Objekt "this" wird nicht gesperrt, sondern das Objekt "this" wird als Mutex verwendet, und es wird verhindert, dass der Body gleichzeitig mit anderen Codeabschnitten ausgeführt wird, die ebenfalls mit "this" synchronisiert sind. Es hat keine Auswirkung auf andere Felder / Methoden von "this", die nicht synchronisiert sind.a
undb
waren Objekte, z. B.Integer
s, haben Sie beim Anwenden des Operators auf Instanzen synchronisiert, die Sie durch andere Objekte ersetzen++
.In der Methodendeklaration ist syntaktischer Zucker dafür synchronisiert:
Bei einer statischen Methode ist es syntaktischer Zucker dafür:
Ich denke, wenn die Java-Designer damals gewusst hätten, was jetzt über Synchronisation verstanden wird, hätten sie den syntaktischen Zucker nicht hinzugefügt, da dies häufig zu schlechten Implementierungen der Parallelität führt.
quelle
Aus "The Java ™ Tutorials" zu synchronisierten Methoden :
Aus "The Java ™ Tutorials" zu synchronisierten Blöcken :
(Hervorhebung von mir)
Angenommen, Sie haben 2 nicht verschachtelte Variablen. Sie möchten also gleichzeitig von einem anderen Thread aus auf jeden zugreifen. Sie müssen die Sperre nicht für die Objektklasse selbst definieren, sondern für die Klasse Object wie unten (Beispiel aus dem zweiten Oracle-Link):
quelle
Die Sperre, auf die zugegriffen wird, bezieht sich auf das Objekt und nicht auf die Methode. Auf welche Variablen innerhalb der Methode zugegriffen wird, spielt keine Rolle.
Das Hinzufügen von "synchronisiert" zur Methode bedeutet, dass der Thread, in dem der Code ausgeführt wird, die Sperre für das Objekt erhalten muss, bevor Sie fortfahren können. Das Hinzufügen von "statisch synchronisiert" bedeutet, dass der Thread, in dem der Code ausgeführt wird, die Sperre für das Klassenobjekt erhalten muss, bevor Sie fortfahren können. Alternativ können Sie Code in einen Block wie folgt einschließen:
Damit können Sie das Objekt angeben, dessen Sperre erworben werden muss.
Wenn Sie das Sperren des enthaltenen Objekts vermeiden möchten, können Sie zwischen folgenden Optionen wählen:
quelle
Von der Oracle - Dokumentation Link
Das Synchronisieren von Methoden hat zwei Auswirkungen:
Werfen Sie einen Blick auf dieser Dokumentation Seite intrinsische Sperren und Sperrverhalten zu verstehen.
Dies beantwortet Ihre Frage: Auf demselben Objekt x können Sie x.addA () und x.addB () nicht gleichzeitig aufrufen, wenn eine der synchronisierten Methoden ausgeführt wird.
quelle
Wenn Sie einige Methoden haben, die nicht synchronisiert sind und auf die Instanzvariablen zugreifen und diese ändern. In Ihrem Beispiel:
Eine beliebige Anzahl von Threads kann gleichzeitig auf diese nicht synchronisierten Methoden zugreifen, wenn sich ein anderer Thread in der synchronisierten Methode desselben Objekts befindet, und Änderungen an Instanzvariablen vornehmen. Zum Beispiel: -
Sie müssen das Szenario vermeiden, dass nicht synchronisierte Methoden auf die Instanzvariablen zugreifen und diese ändern, da es sonst keinen Sinn macht, synchronisierte Methoden zu verwenden.
Im folgenden Szenario: -
Nur einer der Threads kann sich entweder in der addA- oder der addB-Methode befinden, gleichzeitig kann jedoch eine beliebige Anzahl von Threads in die changeState-Methode eingegeben werden. Keine zwei Threads können gleichzeitig addA und addB eingeben (aufgrund der Sperre auf Objektebene), aber gleichzeitig können beliebig viele Threads changeState eingeben.
quelle
Sie können Folgendes tun. In diesem Fall verwenden Sie die Sperre für a und b zum Synchronisieren anstelle der Sperre für "this". Wir können int nicht verwenden, da primitive Werte keine Sperren haben, daher verwenden wir Integer.
quelle
Ja, die andere Methode wird blockiert, da die synchronisierte Methode wie angegeben auf das WHOLE- Klassenobjekt angewendet wird. Trotzdem wird die Ausführung des anderen Threads NUR blockiert, während die Summe in der eingegebenen Methode addA oder addB ausgeführt wird, denn wenn sie beendet ist ... der eine Thread befreit das Objekt und der andere Thread greift auf die andere Methode zu und so weiter.
Ich meine, das "synchronisierte" ist genau dafür gemacht, den anderen Thread daran zu hindern, während einer bestimmten Codeausführung auf einen anderen zuzugreifen. SO ENDLICH FUNKTIONIERT DIESER CODE FEIN.
Wenn es eine 'a'- und eine' b'-Variable gibt, nicht nur eine eindeutige Variable 'a' oder einen anderen Namen, müssen diese Methoden nicht synchronisiert werden, da der Zugriff auf andere Variablen (anderer Speicher) absolut sicher ist Ort).
Wird auch funktionieren
quelle
Dieses Beispiel (obwohl nicht hübsch) bietet mehr Einblick in den Sperrmechanismus. Wenn Inkremente werden synchronisiert und incrementB ist nicht synchronisiert , dann incrementB wird so schnell wie möglich ausgeführt werden, aber wenn incrementB ebenfalls synchronisiert dann muss es ‚wait‘ für Inkremente bis zum Ende, bevor incrementB seine Arbeit erledigen kann.
Beide Methoden werden für ein einzelnes Instanzobjekt aufgerufen. In diesem Beispiel ist es: job , und 'konkurrierende' Threads sind aThread und main . .
Versuchen Sie es mit ' synchronisiert ' in inkrementB und ohne es und Sie werden unterschiedliche Ergebnisse sehen. Wenn inkrementB ebenfalls ' synchronisiert ' ist, muss es warten, bis inkrementA () beendet ist. Führen Sie jede Variante mehrmals aus.
quelle
Wenn ein Thread bei der Java-Synchronisierung eine Synchronisierungsmethode eingeben möchte, wird er für alle synchronisierten Methoden dieses Objekts gesperrt, nicht nur für eine synchronisierte Methode, die der Thread verwendet. Ein Thread, der addA () ausführt, erhält also eine Sperre für addA () und addB (), da beide synchronisiert sind. Andere Threads mit demselben Objekt können addB () also nicht ausführen.
quelle
Dies funktioniert möglicherweise nicht, da das Boxen und Autoboxen von Integer nach int und umgekehrt von JVM abhängt und die Wahrscheinlichkeit groß ist, dass zwei verschiedene Nummern an dieselbe Adresse gehasht werden, wenn sie zwischen -128 und 127 liegen.
quelle