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?

28voto

Peter Lawrey Punkte 511323

Nota: statisch synchronisierte Methoden und Blöcke arbeiten mit dem Objekt Klasse.

public class MyClass {
   // locks MyClass.class
   public static synchronized void foo() {
// do something
   }

   // similar
   public static void foo() {
      synchronized(MyClass.class) {
// do something
      }
   }
}

18voto

Mohammad Adil Punkte 43907

Wenn der Java-Compiler Ihren Quellcode in Bytecode umwandelt, behandelt er synchronisierte Methoden und synchronisierte Blöcke sehr unterschiedlich.

Wenn die JVM eine synchronisierte Methode ausführt, erkennt der ausführende Thread, dass in der method_info-Struktur der Methode das ACC_SYNCHRONIZED-Flag gesetzt ist, erwirbt dann automatisch die Sperre des Objekts, ruft die Methode auf und gibt die Sperre frei. Wenn eine Ausnahme auftritt, gibt der Thread die Sperre automatisch wieder frei.

Die Synchronisierung eines Methodenblocks umgeht dagegen die in der JVM eingebaute Unterstützung für den Erwerb der Sperre eines Objekts und die Behandlung von Ausnahmen und erfordert, dass die Funktionalität explizit in Bytecode geschrieben wird. Wenn Sie den Bytecode für eine Methode mit einem synchronisierten Block lesen, werden Sie mehr als ein Dutzend zusätzlicher Operationen zur Verwaltung dieser Funktionalität sehen.

Hier werden Aufrufe zur Erzeugung einer synchronisierten Methode und eines synchronisierten Blocks gezeigt:

public class SynchronizationExample {
    private int i;

    public synchronized int synchronizedMethodGet() {
        return i;
    }

    public int synchronizedBlockGet() {
        synchronized( this ) {
            return i;
        }
    }
}

Le site synchronizedMethodGet() Methode erzeugt den folgenden Bytecode:

0:  aload_0
1:  getfield
2:  nop
3:  iconst_m1
4:  ireturn

Und hier ist der Bytecode aus der synchronizedBlockGet() Methode:

0:  aload_0
1:  dup
2:  astore_1
3:  monitorenter
4:  aload_0
5:  getfield
6:  nop
7:  iconst_m1
8:  aload_1
9:  monitorexit
10: ireturn
11: astore_2
12: aload_1
13: monitorexit
14: aload_2
15: athrow

Ein signifikanter Unterschied zwischen einer synchronisierten Methode und einem Block besteht darin, dass ein synchronisierter Block im Allgemeinen den Umfang der Sperre reduziert. Da der Umfang der Sperre umgekehrt proportional zur Leistung ist, ist es immer besser, nur kritische Abschnitte des Codes zu sperren. Eines der besten Beispiele für die Verwendung eines synchronisierten Blocks ist doppelt geprüftes Sperren im Singleton-Muster wo statt der Sperrung ganzer getInstance() Methode sperren wir nur den kritischen Abschnitt des Codes, der zur Erstellung der Singleton-Instanz verwendet wird. Dies verbessert die Leistung drastisch, da das Sperren nur ein oder zwei Mal erforderlich ist.

Bei der Verwendung von synchronisierten Methoden müssen Sie besonders vorsichtig sein, wenn Sie sowohl statische synchronisierte als auch nicht-statische synchronisierte Methoden mischen.

12voto

Clint Punkte 8832

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.

Im folgenden Code wird ein Thread, der die Liste ändert, nicht blockiert, wenn er auf einen Thread wartet, der die Karte ändert. Wären die Methoden auf dem Objekt synchronisiert, müsste jede Methode warten, auch wenn die Änderungen, die sie vornehmen, nicht in Konflikt stehen würden.

private List<Foo> myList = new ArrayList<Foo>();
private Map<String,Bar) myMap = new HashMap<String,Bar>();

public void put( String s, Bar b ) {
  synchronized( myMap ) {
    myMap.put( s,b );
    // then some thing that may take a while like a database access or RPC or notifying listeners
  }
}

public void hasKey( String s, ) {
  synchronized( myMap ) {
    myMap.hasKey( s );
  }
}

public void add( Foo f ) {
  synchronized( myList ) {
    myList.add( f );
// then some thing that may take a while like a database access or RPC or notifying listeners
  }
}

public Thing getMedianFoo() {
  Foo med = null;
  synchronized( myList ) {
    Collections.sort(myList);
    med = myList.get(myList.size()/2); 
  }
  return med;
}

7voto

Paul Tomblin Punkte 172816

Mit synchronisierten Blöcken können Sie mehrere Synchronisierer haben, so dass mehrere gleichzeitige, aber nicht konkurrierende Dinge gleichzeitig ablaufen können.

6voto

Kojotak Punkte 1943

Synchronisierte Methoden können mit der Reflection-API überprüft werden. Dies kann für das Testen einiger Verträge nützlich sein, wie z.B. alle Methoden im Modell sind synchronisiert .

Das folgende Snippet gibt alle synchronisierten Methoden von Hashtable aus:

for (Method m : Hashtable.class.getMethods()) {
        if (Modifier.isSynchronized(m.getModifiers())) {
            System.out.println(m);
        }
}

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