2015-07-27 15 views
18

diesen Code vor:Java synchronisierte Methode

public synchronized void onSignalsTimeout(List<SignalSpec> specs) { 
    if (specs != null && specs.size() > 0) { 
     for (SignalSpec spec : specs) { 
      ParsedCANSignal timeoutedSignal = new ParsedCANSignal(); 
      SignalsProvider.getInstance().setSignal(spec.name, spec.parent.parent.channel, timeoutedSignal); 
     } 
    } 
} 

ich einfache Frage haben: Wenn Thread 1 Anrufe onSignalsTimeout Verfahren kann Thread 2 Zugriff auf Objekte, die in diesem Verfahren zugegriffen werden?

Kann nirgendwo finden, wenn 'synchronisiert' nur den Zugriff auf diese Methode oder den Zugriff auf alle in dieser Methode verwendeten Objekte sperrt.

Antwort

49

Zunächst einmal vergessen synchronisiert Methoden. Eine so genannte synchronisierte Methode ...

synchronized AnyType foobar(...) { 
    doSomething(); 
} 

ist nichts anderes als eine Verknüpfung Weg, dies zu schreiben:

AnyType foobar(...) { 
    synchronized(this) { 
     doSomething(); 
    } 
} 

Es ist nichts Besonderes über die Methode in jedem Fall. Was besonders ist, ist der synchronisierte Block, und was ein synchronisierter Block macht, ist sehr einfach. Wenn die JVM führt diese:

synchronized(foo) { 
    doSomething(); 
} 

Es wertet zunächst die Expression foo. Das Ergebnis muss eine Objektreferenz sein. Dann sperrt es das Objekt, führt den Rumpf des Blocks synchronized aus und entsperrt das Objekt.

Aber was bedeutet gesperrt bedeuten? Es kann bedeuten, weniger als Sie denken. Es tut nicht verhindern, dass andere Threads das Objekt verwenden.Es hindert sie nicht daran, auf die Felder des Objekts zuzugreifen oder die Felder zu aktualisieren. Das Sperren eines Objekts verhindert nur, dass andere Threads dasselbe Objekt nicht gleichzeitig sperren können.

Wenn Thread A versucht, synchronized(foo) {...} einzugeben, während Thread B bereits foo gesperrt ist (entweder im selben synchronized Block oder in einem anderen), wird Thread A gezwungen zu warten, bis Thread B die Sperre aufhebt.


Sie verwenden synchronized Blöcke Daten zu schützen.

Angenommen, Ihr Programm verfügt über eine Sammlung von Objekten, die sich in verschiedenen -Status befinden können. Nehmen wir an, dass einige Zustände sinnvoll sind, aber es gibt andere Zustände, die keinen Sinn ergeben. ungültig Staaten.

Angenommen, es ist nicht möglich, dass ein Thread die Daten von einem gültigen Status in einen anderen gültigen Status ändert, ohne dass vorübergehend einen ungültigen Status erstellt.

Wenn Sie den Code setzen, der den Zustand in einem synchronized(foo) Block ändert, und Sie setzen jeden Codeblock, der der Zustand in einen synchronisierten Block sehen, der die gleiche Objekt sperrt, foo Sie dann verhindert, dass andere Threads den temporären ungültigen Status sehen.

+2

Ihre Erklärung ist sehr nett und leicht zu verstehen. Da Sie mehr ins Detail gegangen sind, muss ich fragen ... wo werden andere Threads für das Entsperren gesperrt (warten), wenn ein Thread das Objekt sperrt? Ich kenne seine wahrscheinlich "Debugging" -Frage, aber als ich alle Threads während meines Deadlocks suspendierte, war ich verwirrt, weil ich zwei Threads fand, die beide die gleiche synchronisierte Methode ausführten - ich würde einen am Anfang erwarten und einen zu Beginn eines anderen synchronisieren Methode (um eine Schleife zu erstellen). – arenaq

+0

@arenaq _Wohin?_ wie würde ein Debugger Ihnen zeigen? Ich weiß es nicht. Ich habe in Debuggern nicht viel Java-Code angeschaut. Ich bin eher ein C-Programmierer. Die Synchronisation ist keine intrinsische Sprachfunktion in C, daher zeigt der Debugger in C den Thread, der in einem Synchronisationssystemaufruf gestoppt wurde, von innerhalb eines Aufrufs zu einer Synchronisationsbibliotheksfunktion von irgendwo in meinem Code. Die Java-Debugger, die ich verwendet habe, zeigen keine Systemaufrufe oder die inneren Abläufe der JVM, und ich erinnere mich nicht, jemals den Stapel eines Java-Threads, der auf eine Sperre wartete, zu untersuchen. –

+0

Vergiss es, sein nicht verwandtes Q sowieso ... sollte ein neues Thema sein. – arenaq

3

In diesem Kontext sperrt synchronized gleichzeitig diese Methode und jede andere in Ihrer Klasse als synchronized markierte Methode.

+0

Also, wenn ich 2 synchronisierte Methoden hätte, die auf eine Datenstruktur zugreifen und eine von einem Thread und die andere vom 2. Thread aufrufen, wäre die Synchronisation völlig nutzlos? – arenaq

+0

Sie können Dinge so arrangieren, dass die Datenstruktur nur durch Aufruf einer Funktion aufgerufen werden kann, die Sie als * synchronisiert * markieren. – Bathsheba

+0

Wenn 2 Methoden mit 'synchronized' gekennzeichnet sind, kann' thread1' nicht auf 'method1' zugreifen, während' thread2' 'method2' ausführt. – Codebender

5

Ja, andere Threads können auf die in der Methode verwendeten Objekte zugreifen; Das synchronisierte Schlüsselwort garantiert, dass nicht mehr als ein Thread gleichzeitig den Code der Methode ausführen kann.

Von https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html:

  • Erstens ist es nicht möglich, dass zwei Anrufungen von synchronisierten Methoden auf demselben Objekt verschachteln. Wenn ein Thread eine synchronisierte Methode für ein Objekt ausführt, werden alle anderen Threads, die aufrufen, synchronisierte Methoden für denselben Objektblock (Ausführung aussetzen) , bis der erste Thread mit dem Objekt ausgeführt wird.
  • Zweitens, wenn eine synchronisierte Methode beendet wird, stellt sie automatisch eine "happen-before" -Beziehung mit einem nachfolgenden Aufruf einer synchronisierten Methode für dasselbe Objekt her. Diese garantiert, dass Änderungen des Status des Objekts für alle Threads sichtbar sind. Beachten Sie, dass Konstruktoren nicht synchronisiert werden können. Das synchronisierte Schlüsselwort mit einem Konstruktor ist ein Syntaxfehler. Das Synchronisieren von Konstruktoren ist nicht sinnvoll, da nur der Thread , der ein Objekt erstellt, Zugriff darauf haben soll, während konstruiert wird.
+0

Aber ich kann immer noch auf andere (synchronisierte) Methoden des Objekts zugreifen, wenn das eine von einem anderen Thread ausgeführt wurde, oder? – arenaq

+0

nein, wie Bathsheba bereits schrieb, beziehen sich alle Methoden, die als _synchronized_ in der Klasse markiert sind, auf die Instanz des Objekts für den Monitor. Wenn also eine der Methoden ausgeführt wird, wird die Sperre auf dem Monitor genommen und jeder andere Thread muss warten Sie auf seine Freigabe, um eine als _synchronized_ markierte Methode auszuführen. –

+0

Betrachte Instanz eines Objekts (meine Beispielmethode stammt von Singleton). Dieses Objekt hat method1 und method2, beide sind synchronisiert. Kann ein anderer Thread Methode1 oder zumindest Methode3, die nicht synchronisiert ist, aufrufen, wenn ein Thread die Methode method1 für diese Singleton-Klasse aufruft? – arenaq

Verwandte Themen