421 Stimmen

Gibt es einen Vorteil, eine synchronisierte Methode anstelle eines synchronisierten Blocks zu verwenden?

Kann mir jemand den Vorteil einer synchronisierten Methode gegenüber einem synchronisierten Block anhand eines Beispiels erläutern?

451voto

OscarRyz Punkte 189898

Kann mir jemand den Vorteil der synchronisierten Methode gegenüber dem synchronisierten Block anhand eines Beispiels erläutern? Danke!

Es gibt keinen eindeutigen Vorteil der synchronisierten Methode gegenüber der Blockmethode.

Der einzige Vorteil (den ich aber nicht als Vorteil bezeichnen würde) ist vielleicht, dass Sie den Objektverweis nicht angeben müssen. this .

Methode:

public synchronized void method() { // blocks "this" from here.... 
    ...
    ...
    ...
} // to here

Block:

public void method() { 
    synchronized( this ) { // blocks "this" from here .... 
        ....
        ....
        ....
    }  // to here...
}

Sehen Sie? Überhaupt kein Vorteil.

Blöcke tun haben jedoch Vorteile gegenüber Methoden, vor allem in Bezug auf die Flexibilität, da Sie ein anderes Objekt als Sperre verwenden können, während die Synchronisierung der Methode das gesamte Objekt sperren würde.

Vergleichen Sie:

// locks the whole object
... 
private synchronized void someInputRelatedWork() {
    ... 
}
private synchronized void someOutputRelatedWork() {
    ... 
}

vs.

// Using specific locks
Object inputLock = new Object();
Object outputLock = new Object();

private void someInputRelatedWork() {
    synchronized(inputLock) { 
        ... 
    } 
}
private void someOutputRelatedWork() {
    synchronized(outputLock) { 
        ... 
    }
}

Auch wenn die Methode wächst, können Sie den synchronisierten Abschnitt noch getrennt halten:

 private void method() {
     ... code here
     ... code here
     ... code here
    synchronized( lock ) { 
        ... very few lines of code here
    }
     ... code here
     ... code here
     ... code here
     ... code here
}

143voto

jcrossley3 Punkte 11196

Der einzige wirkliche Unterschied ist, dass ein synchronisierter Block wählen kann, auf welches Objekt er synchronisiert. Eine synchronisierte Methode kann nur 'this' (oder die entsprechende Klasseninstanz für eine synchronisierte Klassenmethode). Diese sind zum Beispiel semantisch äquivalent:

synchronized void foo() {
  ...
}

void foo() {
    synchronized (this) {
      ...
    }
}

Letztere ist flexibler, da sie sich um die damit verbundene Sperre von cualquier Objekt, oft eine Mitgliedsvariable. Es ist auch granularer, weil Sie gleichzeitigen Code haben können, der vor und nach dem Block, aber immer noch innerhalb der Methode ausgeführt wird. Natürlich können Sie genauso gut eine synchronisierte Methode verwenden, indem Sie den gleichzeitigen Code in separate, nicht synchronisierte Methoden umstrukturieren. Verwenden Sie das, was den Code verständlicher macht.

78voto

iny Punkte 7005

Synchronisierte Methode

Vorteile:

  • Ihre IDE kann die synchronisierten Methoden anzeigen.
  • Die Syntax ist kompakter.
  • Erzwingt die Aufteilung der synchronisierten Blöcke in separate Methoden.

Nachteile:

  • Synchronisiert sich mit diesem und ermöglicht es somit auch Außenstehenden, sich mit diesem zu synchronisieren.
  • Es ist schwieriger, Code außerhalb des synchronisierten Blocks zu verschieben.

Synchronisierter Block

Vorteile:

  • Ermöglicht die Verwendung einer privaten Variable für die Sperre und zwingt so die Sperre, innerhalb der Klasse zu bleiben.
  • Synchronisierte Blöcke können durch die Suche nach Referenzen auf die Variable gefunden werden.

Nachteile:

  • Die Syntax ist komplizierter und macht den Code schwieriger zu lesen.

Ich persönlich ziehe es vor, synchronisierte Methoden mit Klassen zu verwenden, die sich nur auf die Sache konzentrieren, die synchronisiert werden muss. Eine solche Klasse sollte so klein wie möglich sein, damit es einfach ist, die Synchronisation zu überprüfen. Andere sollten sich nicht um die Synchronisation kümmern müssen.

36voto

cdecker Punkte 4267

Der Hauptunterschied besteht darin, dass Sie bei Verwendung eines synchronisierten Blocks auf ein anderes Objekt als este was eine viel größere Flexibilität ermöglicht.

Angenommen, Sie haben eine Nachrichtenwarteschlange und mehrere Nachrichtenproduzenten und -konsumenten. Wir wollen nicht, dass sich die Produzenten gegenseitig stören, aber die Konsumenten sollen Nachrichten abrufen können, ohne auf die Produzenten warten zu müssen. Wir erstellen also einfach ein Objekt

Object writeLock = new Object();

Und von nun an wird jedes Mal, wenn ein Hersteller eine neue Nachricht hinzufügen möchte, diese einfach gesperrt:

synchronized(writeLock){
  // do something
}

Die Verbraucher können also weiterhin lesen, und die Produzenten werden gesperrt.

31voto

sudheer Punkte 311

Synchronisierte Methode

Synchronisierte Methoden haben zwei Auswirkungen.
Erstens, wenn ein Thread eine synchronisierte Methode für ein Objekt ausführt, blockieren alle anderen Threads, die synchronisierte Methoden für dasselbe Objekt aufrufen, die Ausführung, bis der erste Thread mit dem Objekt fertig ist.

Zweitens: Wenn eine synchronisierte Methode beendet wird, stellt sie automatisch eine "happens-before"-Beziehung zu jedem nachfolgenden Aufruf einer synchronisierten Methode für dasselbe Objekt her. Dies garantiert, dass Änderungen am Zustand des Objekts für alle Threads sichtbar sind.

Beachten Sie, dass Konstruktoren nicht synchronisiert werden können - die Verwendung des Schlüsselworts synchronized mit einem Konstruktor ist ein Syntaxfehler. Die Synchronisierung von Konstruktoren ist nicht sinnvoll, da nur der Thread, der ein Objekt erstellt, Zugriff auf dieses haben sollte, während es erstellt wird.

Synchronisierte Anweisung

Im Gegensatz zu synchronisierten Methoden muss bei synchronisierten Anweisungen das Objekt angegeben werden, das die intrinsische Sperre bereitstellt: Meistens verwende ich dies, um den Zugriff auf eine Liste oder Karte zu synchronisieren, aber ich möchte nicht den Zugriff auf alle Methoden des Objekts blockieren.

F: Intrinsische Sperren und Synchronisierung Die Synchronisierung basiert auf einer internen Entität, die als intrinsische Sperre oder Monitorsperre bezeichnet wird. (In der API-Spezifikation wird diese Entität oft einfach als "Monitor" bezeichnet.) Intrinsische Sperren spielen bei beiden Aspekten der Synchronisierung eine Rolle: Erzwingen des exklusiven Zugriffs auf den Zustand eines Objekts und Herstellen von Vorbeifahrtsbeziehungen, die für die Sichtbarkeit wichtig sind.

Jedes Objekt ist mit einer eigenen Sperre versehen. Konventionell muss ein Thread, der exklusiven und konsistenten Zugriff auf die Felder eines Objekts benötigt, die intrinsische Sperre des Objekts erwerben, bevor er auf sie zugreift, und die intrinsische Sperre wieder freigeben, wenn er mit ihnen fertig ist. Ein Thread besitzt die intrinsische Sperre zwischen dem Zeitpunkt, an dem er die Sperre erworben hat, und dem Zeitpunkt, an dem er sie wieder freigibt. Solange ein Thread eine intrinsische Sperre besitzt, kann kein anderer Thread die gleiche Sperre erwerben. Der andere Thread wird blockiert, wenn er versucht, die Sperre zu erlangen.

package test;

public class SynchTest implements Runnable {  
    private int c = 0;

    public static void main(String[] args) {
        new SynchTest().test();
    }

    public void test() {
        // Create the object with the run() method
        Runnable runnable = new SynchTest();
        Runnable runnable2 = new SynchTest();
        // Create the thread supplying it with the runnable object
        Thread thread = new Thread(runnable,"thread-1");
        Thread thread2 = new Thread(runnable,"thread-2");
//      Here the key point is passing same object, if you pass runnable2 for thread2,
//      then its not applicable for synchronization test and that wont give expected
//      output Synchronization method means "it is not possible for two invocations
//      of synchronized methods on the same object to interleave"

        // Start the thread
        thread.start();
        thread2.start();
    }

    public synchronized  void increment() {
        System.out.println("Begin thread " + Thread.currentThread().getName());
        System.out.println(this.hashCode() + "Value of C = " + c);
//      If we uncomment this for synchronized block, then the result would be different
//      synchronized(this) {
            for (int i = 0; i < 9999999; i++) {
                c += i;
            }
//      }
        System.out.println("End thread " + Thread.currentThread().getName());
    }

//    public synchronized void decrement() {
//        System.out.println("Decrement " + Thread.currentThread().getName());
//    }

    public int value() {
        return c;
    }

    @Override
    public void run() {
        this.increment();
    }
}

Überprüfen Sie verschiedene Ausgaben mit synchronisierter Methode, Block und ohne Synchronisierung.

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