Frage

Kann jemand mir sagen, den Vorteil der synchronisierten Verfahren über synchronisierten Block mit einem Beispiel?

War es hilfreich?

Lösung

  

Kann mir jemand sagen, den Vorteil des synchronisierten Verfahren über den synchronisierten Block mit einem Beispiel? Danke.

Es ist kein klarer Vorteil der synchronisierten Verfahren über den Block verwenden.

Vielleicht ist das nur eine (aber ich würde es nicht von Vorteil) ist, dass Sie nicht den Objektverweis this enthalten müssen.

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? Kein Vorteil überhaupt.

Blöcke tun haben Vorteile gegenüber Verfahren aber meist in Flexibilität, weil Sie ein anderes Objekt als Sperre verwenden kann, während die Methode der Synchronisierung das gesamte Objekt sperren würde.

vergleichen:

// 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 man noch den synchronisierten Abschnitt 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
}

Andere Tipps

Der einzige wirkliche Unterschied besteht darin, dass ein synchronisierten Block wählen kann, welches Objekt sie synchronisiert auf. Eine synchronisierte Methode kann nur verwenden 'this' (oder die entsprechende Klasseninstanz für ein synchronisiertes Klassenmethode). Zum Beispiel sind diese semantisch äquivalent:

synchronized void foo() {
  ...
}

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

Letzteres ist flexibler, da sie für die zugeordnete Sperre von konkurrieren kann jeder Objekt, oft eine Membervariable. Es ist auch eine detailliertere, weil Sie vor gleichzeitigen Ausführung von Code haben könnten und nach dem Block, aber immer noch innerhalb des Verfahrens. Natürlich könnten Sie genauso gut eine synchronisierte Methode durch den gleichzeitigen Code in separate nicht-synchronisierten Methoden Refactoring. Verwenden Sie je nachdem, was der Code verständlicher macht.

synchronisierte Methode

Vorteile:

  • Ihre IDE können die synchronisierten Methoden an.
  • Die Syntax ist kompakter.
  • Forces die synchronisierten Blöcke auf verschiedene Methoden spalten.

Nachteile:

  • Synchronisiert auf diese und so ist es möglich, für Außenstehende zu, um es zu synchronisieren.
  • Es ist schwieriger zu Code außerhalb des synchronisierten Block zu verschieben.

Synchronized Block

Vorteile:

  • Ermöglicht eine private Variable für das Schloss mit und so zwingt die Sperre innerhalb der Klasse zu bleiben.
  • Synchronisierte Blöcke können durch die Suche Verweise auf die Variable gefunden werden.

Nachteile:

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

Persönlich bevorzuge ich synchronisierte Methoden mit Klassen konzentriert sich nur auf die Sache, um die Synchronisation. Eine solche Klasse sollte so klein wie möglich sein, und so sollte es leicht sein, um die Synchronisation zu überprüfen. Andere sollen nicht brauchen, um über die Synchronisation sorgen.

Der wesentliche Unterschied besteht darin, dass, wenn Sie einen synchronisierten Block verwenden Sie auf einem Objekt sperren können andere als das , die viel flexibler sein kann.

Angenommen, Sie eine Nachrichtenwarteschlange und mehrere Nachrichten Produzenten und Konsumenten haben. Wir wollen nicht, Produzenten miteinander stören, aber die Verbraucher sollten Nachrichten abrufen können, ohne für die Produzenten zu warten. Also haben wir nur ein Objekt erstellen

Object writeLock = new Object();

Und von nun an jedes Mal ein Hersteller will eine neue Mitteilung addieren wir, dass sperren nur:

synchronized(writeLock){
  // do something
}

So kann der Verbraucher immer noch lesen, und Produzenten gesperrt werden.

Synchronisierte Methode

Synchronisierte Methoden haben zwei Effekte.
Zuerst wird, wenn ein Thread eine synchronisierte Methode für ein Objekt ausgeführt wird, werden alle anderen Threads, die Methoden für die gleiche Objektblock (Ausführungs suspendieren), bis der erste Thread synchronisiert invoke wird mit dem Objekt durchgeführt.

Zweitens, wenn ein synchronisiertes Verfahren beendet wird, es automatisch eine geschieht vor-Beziehung mit jedem nachfolgenden Aufruf eines synchronisierten Verfahrens für dasselbe Objekt. Damit ist gewährleistet, dass Änderungen an dem Zustand des Objekts an alle Threads sichtbar sind.

Beachten Sie, dass Konstrukteure können nicht synchronisiert werden - das synchronisierte Schlüsselwort mit einem Konstruktor ist ein Syntaxfehler. macht Konstrukteuren Synchronisieren nicht sinnvoll, da nur der Thread, der ein Objekt erstellt sollte darauf Zugriff hat, während es gebaut wird.

Synchronisierte Statement

Im Gegensatz zu synchronisierten Methoden, Synchronized-Anweisungen müssen Sie das Objekt angeben, die die innere Sperre bestimmt: Am häufigsten verwende ich diesen Zugriff auf eine Liste zu synchronisieren oder eine Karte, aber ich will nicht den Zugriff auf alle Methoden des Objekts blockieren.

F: Intrinsic Schlösser und Synchronisation Die Synchronisation ist um eine interne Einheit, bekannt als die intrinsische Schloss oder Monitorverriegelung gebaut. (Die API-Spezifikation bezieht sich oft auf diese Entität einfach als „Monitor“.) Intrinsic Schlösser spielen eine Rolle bei beiden Aspekten der Synchronisation: Durchsetzung exklusiven Zugriff auf ein Zustand des Objekts und zur Erstellung geschieht-vor Beziehungen, der Sichtbarkeit von wesentlicher Bedeutung sind.

Jedes Objekt hat eine innere Sperre mit ihm verbunden ist. Vereinbarungsgemäß wird ein Thread, der auf ein Objektfeld exklusiven und konsistenten Zugriff benötigt hat, um das innere Sperre des Objekts zu erwerben, bevor sie Zugriff auf und lassen Sie dann die innere Sperre, wenn er mit ihnen fertig ist. Ein Thread gesagt wird die innere Sperre zwischen der Zeit, besitzen sie die Sperre erworben haben und die Verriegelung gelöst. Solange ein Thread eine intrinsische Sperre besitzt, kann kein anderer Thread die gleiche Sperre erwerben. Der andere Thread wird blockiert, wenn es versucht, die Sperre zu erwerben.

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();
    }
}

Cross-Check verschiedene Ausgänge mit synchronisierten Verfahren, Block und ohne Synchronisation.

. Hinweis: statisch synchronisierten Methoden und Blöcke auf dem Class-Objekt arbeiten

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

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

Wenn Java-Compiler den Quellcode zu Byte-Code konvertiert, es behandelt synchronisierte Methoden und synchronisierte Blöcke sehr unterschiedlich.

Wenn die JVM eine synchronisierte Methode ausgeführt wird, identifiziert die Ausführung von Thread, der die Struktur des method_info Verfahren die ACC_SYNCHRONIZED-Flag gesetzt hat, so wird automatisch er die Sperre des Objekts erfasst, ruft die Methode, und gibt die Sperre. Wenn eine Ausnahme auftritt, gibt den Faden automatisch die Sperre.

ein Verfahren Block synchronisieren, auf der anderen Seite, umgeht die JVM integrierte Unterstützung für eine Objektsperre und Ausnahmebehandlung zu erwerben und erfordert, dass die Funktionalität explizit in Byte-Code geschrieben werden. Wenn Sie den Byte-Code für ein Verfahren mit einem synchronisierten Block lesen, werden Sie mehr als ein Dutzend weitere Operationen sehen diese Funktionalität zu verwalten.

Dies zeigt, Anrufe zu erzeugen sowohl eine synchronisierte Methode und einen synchronisierten Block:

public class SynchronizationExample {
    private int i;

    public synchronized int synchronizedMethodGet() {
        return i;
    }

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

Die synchronizedMethodGet() Verfahren erzeugt die folgenden Bytecode:

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

Und hier ist der Byte-Code 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 synchronisierte Methode und Block ist, dass, Synchronblock im allgemeinen Umfang der Sperre reduzieren. Als Rahmen der Sperre umgekehrt proportional zur Leistung ist, ist es immer besser, nur kritischen Abschnitt des Codes zu sperren. Eines der besten Beispiel für synchronisierten Block mit doppelt geprüft in Singleton Muster Sperren , wo anstelle von ganzer getInstance() Methode sperren wir sperren nur kritischen Code-Abschnitt, der verwendet wird Singleton Instanz zu erstellen. Dies verbessert die Leistung drastisch, weil Verriegelung ist nur erforderlich, ein oder zwei Mal.

Während synchronisierte Methoden verwenden, müssen Sie besonders vorsichtig, wenn Sie beide statische Synchron mischen und nicht-statische Synchron Methoden.

Am häufigsten verwende ich diesen Zugriff auf eine Liste zu synchronisieren oder eine Karte, aber ich will nicht den Zugriff auf alle Methoden des Objekts blockieren.

Im folgenden Code ein Thread die Änderung der Liste wird nicht für einen Thread wartet blockieren, die die Karte ändern. Wenn die Methoden für das Objekt synchronisiert wurden, dann würde jede Methode warten muß, obwohl die Änderungen sie machen würde nicht in Konflikt.

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;
}

Mit synchronisierten Blöcken können Sie mehrere Synchronisierungen haben, so dass mehrere gleichzeitige, aber nicht in Konflikt Dinge können zur gleichen Zeit weitergehen.

Synchronisierte Methoden können unter Verwendung von Reflection-API überprüft werden. Dies kann zum Testen einige Verträge nützlich sein, wie alle Methoden in Modell synchronisiert .

Das folgende Snippet druckt alle synchronisierten Methoden der Hashtable:

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

Wichtiger Hinweis auf den synchronisierten Block mit: Sie vorsichtig, was Sie als Sperrobjekt verwenden

Das Codefragment aus user2277816 oben veranschaulicht diesen Punkt, dass ein Verweis auf einen String Literal wird als Verriegelungsobjekt verwendet. Erkennen, dass Stringliterale in Java automatisch interniert ist, und Sie sollten beginnen, das Problem zu sehen: jedes Stück Code, der auf dem wörtlichen „Lock“ synchronisiert, teilt die gleiche Sperre! Dies kann leicht mit völlig anderen Teilen des Codes zu Deadlocks führen.

Es ist nicht nur String-Objekte, die Sie müssen vorsichtig sein, mit. Boxed Primitive sind auch eine Gefahr, da Autoboxing und die valueOf Methoden können die gleichen Objekte wiederverwenden, je nach dem Wert.

Weitere Informationen finden Sie unter: https: / /www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused

Oft eine Sperre auf ein Verfahren Ebene verwendet, ist zu grob. Warum sperrt ein Stück Code, die nicht freigegebene Ressourcen nicht zugreifen, indem ein ganzes Verfahren Perren. Da jedes Objekt eine Sperre hat, können Sie Dummy-Objekte erstellen, um Block-Level-Synchronisation zu implementieren. Die Blockebene ist effizienter, weil es nicht das ganze Verfahren nicht sperren.

Hier einige Beispiel

Method Ebene

class MethodLevel {

  //shared among threads
SharedResource x, y ;

public void synchronized method1() {
   //multiple threads can't access
}
public void synchronized method2() {
  //multiple threads can't access
}

 public void method3() {
  //not synchronized
  //multiple threads can access
 }
}

Block Level

class BlockLevel {
  //shared among threads
  SharedResource x, y ;

  //dummy objects for locking
  Object xLock = new Object();
  Object yLock = new Object();

    public void method1() {
     synchronized(xLock){
    //access x here. thread safe
    }

    //do something here but don't use SharedResource x, y
    // because will not be thread-safe
     synchronized(xLock) {
       synchronized(yLock) {
      //access x,y here. thread safe
      }
     }

     //do something here but don't use SharedResource x, y
     //because will not be thread-safe
    }//end of method1
 }

[Bearbeiten]

Für Collection wie Vector und Hashtable sie synchronisiert werden, wenn ArrayList oder HashMap sind nicht und Sie müssen eingestellt synchronisiert Schlüsselwort oder Sammlungen synchronisierte Methode aufrufen:

Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list

Einziger Unterschied: synchronisierten Blöcke ermöglicht granulare Verriegelungs Im Gegensatz synchronisierte Methode

Grundsätzlich synchronized Block oder Methoden verwendet wurde, durch die Vermeidung von Speicherfehlern Inkonsistenz threadsicher Code zu schreiben.

Diese Frage ist sehr alt und viele Dinge haben sich während der letzten 7 Jahre geändert. Neue Programmierkonstrukte für Thread-Sicherheit eingeführt.

Sie können Thread-Sicherheit mithilfe von erweiterten Gleichzeitigkeit API statt synchronied Blöcke erreichen. Diese Dokumentation bietet gute Programmierkonstrukte Thread-Sicherheit zu erreichen.

Sperrobjekte Unterstützung Verriegelungs Idiome, die viele gleichzeitige Anwendungen vereinfachen.

Pfänder definieren ein High-Level-API für die Einleitung und Threads zu verwalten. Executor Implementierungen von java.util.concurrent bereitgestellt bietet Thread-Pool-Management geeignet für großflächige Anwendungen.

Concurrent Collections macht es einfacher, große Sammlungen von Daten zu verwalten, und die Notwendigkeit für die Synchronisation erheblich reduzieren kann.

Atomic Variablen haben Eigenschaften, die Synchronisation minimieren und helfen Speicherkonsistenzfehler zu vermeiden.

ThreadLocalRandom (in JDK 7) bietet eine effiziente Erzeugung von Pseudo-Zufallszahlen von mehreren Threads.

Besserer Ersatz für synchronisiert ist ReentrantLock , die Lock API verwendet

  

Eine einspringende mutual exclusion Sperre mit dem gleichen Grundverhalten und Semantik wie die impliziten Bildschirmsperre zugegriffen synchronisierten Methoden und Anweisungen verwendet, jedoch mit erweiterten Funktionen.

Beispiel mit Sperren:

class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

Siehe java.util .concurrent und java.util.concurrent.atomic Pakete auch für andere Programmierkonstrukte.

auf diese Frage im Zusammenhang Siehe auch:

Synchronisation vs sperren

Synchronisierte Verfahren zur Sperre alle Objekte verwendet Synchronisierten Block wird verwendet, um spezifisches Objekt zu sperren

In der Regel ist dies meist die gleiche außer explizit zu werden über das Monitor-Objekts, das dieses Objekt gegen die impliziten verwendet werden wird. Ein Nachteil der synchronisierten Methoden, die ich denke, manchmal übersehen wird, ist, dass die „diese“ Referenz bei der Verwendung auf die Sie synchronisieren mag die Möglichkeit offen, von externen Objekten auf demselben Objekt zu verriegeln. Das kann ein sehr subtilen Fehler sein, wenn man in sie läuft. Synchronisieren auf einem internen explizites Objekt oder anderem bestehendes Feld kann dieses Problem vermeiden, vollständig die Synchronisation eingekapselt wird.

Wie schon gesagt, hier synchronisierten Block benutzerdefinierte Variablen als Sperrobjekt verwenden kann, wenn synchronisierte Funktion nur „der“ verwendet. Und natürlich können Sie mit Bereichen Ihrer Funktion manipulieren, die synchronisiert werden sollen. Aber jeder sagt, dass kein Unterschied zwischen synchronisierten Funktion und Block, der ganze Funktion „dieses“ als Sperrobjekt abdeckt. Das ist nicht wahr, ist der Unterschied in Byte-Code, der in beiden Situationen erzeugt wird. Im Falle einer synchronisierten Blocknutzung sollten lokale Variable, die Referenz zugewiesen werden, um „dieses“ hält. Und als Ergebnis werden wir etwas größere Größe für die Funktion (nicht relevant, wenn Sie nur wenige Anzahl von Funktionen haben).

Weitere detaillierte Erläuterung des Unterschiedes finden Sie hier: http://www.artima.com/insidejvm/ed2/threadsynchP.html

Bei synchronisierten Methoden Sperre wird auf ein Objekt erworben werden. Aber wenn Sie mit synchronisierten Block gehen haben Sie die Möglichkeit, ein Objekt angeben, auf dem das Schloss erworben werden.

Beispiel:

    Class Example {
    String test = "abc";
    // lock will be acquired on String  test object.
    synchronized (test) {
        // do something
    }

   lock will be acquired on Example Object
   public synchronized void testMethod() {
     // do some thing
   } 

   }

Ich weiß, dass dies eine alte Frage, aber mit meiner schnellen Lesen der Antworten hier, habe ich nicht wirklich jemand sehen erwähnen, dass ein synchronized Verfahren kann die falsch Sperre sein. Von Java Concurrency in der Praxis (S. 72.):

public class ListHelper<E> {
  public List<E> list = Collections.syncrhonizedList(new ArrayList<>());
...

public syncrhonized boolean putIfAbsent(E x) {
 boolean absent = !list.contains(x);
if(absent) {
 list.add(x);
}
return absent;
}

Der obige Code hat das Aussehen des Seins Thread-sicher. Doch in Wirklichkeit ist es nicht. In diesem Fall wird die Sperre für die Instanz der Klasse erhalten. Es ist jedoch möglich, dass die Liste von einem anderen Thread geändert wird, nicht mit dieser Methode. Der richtige Ansatz wäre die Verwendung

public boolean putIfAbsent(E x) {
 synchronized(list) {
  boolean absent = !list.contains(x);
  if(absent) {
    list.add(x);
  }
  return absent;
}
}

Der obige Code würde blockieren alle Themen versuchen zu ändern Liste aus Modifizieren der Liste, bis der synchronisierten Block abgeschlossen wurde.

Als eine praktische Sache, ist der Vorteil der synchronisierten Methoden über synchronisierten Blöcke ist, dass sie mehr Idiot-beständig; weil Sie nicht ein beliebiges Objekt zu erfassen können wählen, können Sie die synchronisierte Methode Syntax mißbrauchen wie Verriegelung an einer Schnur dumme Dinge zu tun, wörtliche oder auf den Inhalt eines wandelbaren Feldverriegelungs, die unter den Fäden verändert heraus wird.

Auf der anderen Seite, mit synchronisierten Methoden Sie die Sperre nicht schützen können von von jedem Thread erworben zu werden, die einen Verweis auf das Objekt erhalten.

So als Modifikator auf Methoden synchronisiert ist besser bei Ihrer Kuh-orkers Schutz vor mich selbst zu verletzen, während mit synchronisierten Blöcken in Verbindung mit privaten endgültigen Sperrobjekten ist besser in Ihren eigenen Code aus dem Kuh-orkers zu schützen.

Aus einer Java-Spezifikation Zusammenfassung: http://www.cs.cornell.edu/andru/javaspec/17 .doc.html

  

Die synchronisierte Anweisung (§14.17) berechnet einen Verweis auf ein Objekt;   es versucht dann, eine Sperre Aktion für das Objekt auszuführen und nicht   geht weiter, bis die Sperre Aktion erfolgreich abgeschlossen wird. ...

     

A synchronisierte Methode (§8.4.3.5) führt automatisch eine Sperre Aktion   wenn es aufgerufen wird; sein Körper nicht ausgeführt wird, bis die Sperre Aktion hat   erfolgreich abgeschlossen. Wenn die Methode eine Instanzmethode ist, es   sperrt die Sperre mit der Instanz zugeordnet sind, für die sie aufgerufen wurde,   (Das heißt, das Objekt, das als dies bei der Ausführung bekannt sein wird von   der Körper des Verfahrens). Wenn die Methode statisch ist, es sperrt die   Schloss mit dem Klasse-Objekt zugeordnet ist, die die Klasse darstellt, in   der die Methode definiert. ...

Auf der Grundlage dieser Beschreibungen, würde ich sagen, die meisten bisherigen Antworten richtig sind, und ein synchronisiertes Verfahren könnte für statische Methoden besonders nützlich sein, wo man sonst herauszufinden würde, wie das „Class-Objekt zu erhalten, die die Klasse darstellt, in denen die Methode definiert wurde. "

Edit: Ich ursprünglich dachte, dass diese Zitate der aktuellen Java-Spezifikation waren. Stellte klar, dass diese Seite ist nur eine Zusammenfassung / Erläuterung der Spezifikation

TLDR; Weder den synchronized Modifikator noch den synchronized(this){...} Ausdruck aber synchronized(myLock){...} wo myLock eine letzte Instanz Feld ist ein privates Objekt hält

.

die Differenz des synchronized Modifikator auf der Methode Erklärung und das synchronized(..){ } Expression im Verfahren Körper zwischen der Verwendung ist diese:

  • Der synchronized Modifikator auf der Methode der Unterschrift angegeben
    1. ist sichtbar in dem generierten JavaDoc,
    2. ist programmatisch bestimmbare über Reflexion wenn eine Methode Modifikator für Modifier.SYNCHRONIZED ,
    3. erfordert weniger tippen und inden im Vergleich zu synchronized(this) { .... } und
    4. (abhängig von Ihren IDE) ist sichtbar in der Klasse Umriss und Code-Vervollständigung,
    5. verwendet das this Objekt als Sperre, wenn sie auf nicht-statische Methode oder der umschließenden Klasse deklariert, wenn sie auf einer statischen Methode deklariert.
  • Die synchronized(...){...} Ausdruck ermöglicht es Ihnen,
    1. , um nur die Ausführung von Teilen des Körpers einer Methode zu synchronisieren,
    2. innerhalb von einem Konstruktor verwendet werden oder ein ( statisch ) Initialisierungsbaustein,
    3. das Sperrobjekt wählen, die den synchronisierten Zugriff steuert.

Um jedoch den synchronized Modifikator oder synchronized(...) {...} mit this als das Verriegelungsobjekt (wie in synchronized(this) {...}), haben den gleichen Nachteil. Beide verwenden seine eigene Instanz als das Verriegelungsobjekt zu synchronisieren auf. Das ist gefährlich, weil nicht nur das Objekt selbst, sondern jede anderer externes Objekt / Code, der eine Referenz auf das Objekt hält es auch als Synchronisierungssperre mit potenziell schweren Nebenwirkungen (Leistungsverschlechterung und Deadlocks ).

Deshalb beste Vorgehensweise ist weder den synchronized Modifikator noch den synchronized(...) Ausdruck in Verbindung mit this als Sperrobjekt, sondern ein Sperrobjekt privat auf dieses Objekt zu verwenden. Zum Beispiel:

public class MyService {
    private final lock = new Object();

    public void doThis() {
       synchronized(lock) {
          // do code that requires synchronous execution
        }
    }

    public void doThat() {
       synchronized(lock) {
          // do code that requires synchronous execution
        }
    }
}

Sie können auch mehrere Sperrobjekte verwenden, aber besondere Sorgfalt erforderlich, um dies zu gewährleisten, ist in Deadlocks nicht zur Folge hat, wenn verwendete verschachtelt.

public class MyService {
    private final lock1 = new Object();
    private final lock2 = new Object();

    public void doThis() {
       synchronized(lock1) {
          synchronized(lock2) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThat() and doMore().
          }
    }

    public void doThat() {
       synchronized(lock1) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThis().
              // doMore() may execute concurrently
        }
    }

    public void doMore() {
       synchronized(lock2) {
              // code here is guaranteed not to be executes at the same time
              // as the synchronized code in doThis().
              // doThat() may execute concurrently
        }
    }
}

Ich nehme diese Frage über den Unterschied zwischen Thread-sicher Singleton und Verzögerte Initialisierung mit Überprüfen Sperren. Ich habe immer zu diesem Artikel beziehen sich, wenn ich einige spezifische Singleton implementieren müssen.

Nun, das ist ein Thread-sicher Singleton :

// Java program to create Thread Safe 
// Singleton class 
public class GFG  
{ 
  // private instance, so that it can be 
  // accessed by only by getInstance() method 
  private static GFG instance; 

  private GFG()  
  { 
    // private constructor 
  } 

 //synchronized method to control simultaneous access 
  synchronized public static GFG getInstance()  
  { 
    if (instance == null)  
    { 
      // if instance is null, initialize 
      instance = new GFG(); 
    } 
    return instance; 
  } 
} 
  

Vorteile:

     
      
  1. Verzögerte Initialisierung möglich.

  2.   
  3. Es ist Thread-sicher.

  4.   
     

Nachteile:

     
      
  1. getInstance () Methode wird synchronisiert, so bewirkt, dass es zu geringer Leistung als mehrere Threads kann es nicht gleichzeitig zugreifen.
  2.   

Dies ist eine Verzögerte Initialisierung mit Überprüfen Verriegelung :

// Java code to explain double check locking 
public class GFG  
{ 
  // private instance, so that it can be 
  // accessed by only by getInstance() method 
  private static GFG instance; 

  private GFG()  
  { 
    // private constructor 
  } 

  public static GFG getInstance() 
  { 
    if (instance == null)  
    { 
      //synchronized block to remove overhead 
      synchronized (GFG.class) 
      { 
        if(instance==null) 
        { 
          // if instance is null, initialize 
          instance = new GFG(); 
        } 

      } 
    } 
    return instance; 
  } 
} 
  

Vorteile:

     
      
  1. Verzögerte Initialisierung möglich.

  2.   
  3. Es ist auch Thread-sicher.

  4.   
  5. Performance reduziert, da synchronisierter Stichwort überwunden wird.

  6.   
     

Nachteile:

     
      
  1. Zum ersten Mal kann die Leistung beeinträchtigt.

  2.   
  3. Als Nachteile. Doppelrückschlag Verfahren Verriegelungs erträglich, so dass es sein kann,   Hochleistungs-Multi-Threaded-Anwendungen verwendet für.

  4.   

Bitte beachten Sie diesen Artikel für weitere Informationen:

https://www.geeksforgeeks.org/java- Singleton-Design-Muster-Praktiken-Beispiele /

Synchronisieren mit Gewinde. 1) NIE synchronisiert nachfolgend () in einem Thread ist es nicht funktioniert. Synchronisieren mit (this) verwendet den aktuellen Thread als Verriegelungs Thread-Objekt. Da jeder Faden unabhängig von anderen Threads ist, gibt es keine Koordination der Synchronisation. 2) Prüfung von Code zeigen, dass in Java 1.6 auf einem Mac die Methode Synchronisation funktioniert nicht. 3) synchronisiert (lockObj) wobei lockObj ist ein gemeinsames gemeinsames Objekt aller Threads Synchronisieren auf es wird funktionieren. 4) ReenterantLock.lock () und .unlock () funktioniert. Siehe Java-Tutorials für diese.

Der folgende Code zeigt diese Punkte. Es enthält auch den Thread-sicheren Vektor, die für die Arraylist ersetzt werden würden, zu zeigen, dass viele Threads zu einem Vektor-Zugabe verlieren keine Informationen, während das gleiche mit einer Arraylist Informationen verlieren. 0) Aktuelle Code zeigt Informationsverlust auf Grund der Rasse Bedingungen A) Kommentar des aktuellen A-Linie markiert ist, und Kommentar- der A-Linie darüber, dann führen, Methode verliert Daten, aber es sollte nicht. B) Rückwärts-Schritt A, B und uncomment // Endblock}. Dann laufen Ergebnisse keinen Datenverlust zu sehen C) Kommentieren Sie B Kommentar- C. Ausführen, siehe Synchronisation auf (diese) verliert Daten, wie erwartet. Verschwenden Sie keine Zeit alle Variationen zu vervollständigen haben, hoffe, das hilft. Wenn die Synchronisation auf (diese) oder die Methode Synchronisation funktioniert, bitte angeben, über welche Version von Java und OS Sie getestet. Danke.

import java.util.*;

/** RaceCondition - Shows that when multiple threads compete for resources 
     thread one may grab the resource expecting to update a particular 
     area but is removed from the CPU before finishing.  Thread one still 
     points to that resource.  Then thread two grabs that resource and 
     completes the update.  Then thread one gets to complete the update, 
     which over writes thread two's work.
     DEMO:  1) Run as is - see missing counts from race condition, Run severa times, values change  
            2) Uncomment "synchronized(countLock){ }" - see counts work
            Synchronized creates a lock on that block of code, no other threads can 
            execute code within a block that another thread has a lock.
        3) Comment ArrayList, unComment Vector - See no loss in collection
            Vectors work like ArrayList, but Vectors are "Thread Safe"
         May use this code as long as attribution to the author remains intact.
     /mf
*/ 

public class RaceCondition {
    private ArrayList<Integer> raceList = new ArrayList<Integer>(); // simple add(#)
//  private Vector<Integer> raceList = new Vector<Integer>(); // simple add(#)

    private String countLock="lock";    // Object use for locking the raceCount
    private int raceCount = 0;        // simple add 1 to this counter
    private int MAX = 10000;        // Do this 10,000 times
    private int NUM_THREADS = 100;    // Create 100 threads

    public static void main(String [] args) {
    new RaceCondition();
    }

    public RaceCondition() {
    ArrayList<Thread> arT = new ArrayList<Thread>();

    // Create thread objects, add them to an array list
    for( int i=0; i<NUM_THREADS; i++){
        Thread rt = new RaceThread( ); // i );
        arT.add( rt );
    }

    // Start all object at once.
    for( Thread rt : arT ){
        rt.start();
    }

    // Wait for all threads to finish before we can print totals created by threads
    for( int i=0; i<NUM_THREADS; i++){
        try { arT.get(i).join(); }
        catch( InterruptedException ie ) { System.out.println("Interrupted thread "+i); }
    }

    // All threads finished, print the summary information.
    // (Try to print this informaiton without the join loop above)
    System.out.printf("\nRace condition, should have %,d. Really have %,d in array, and count of %,d.\n",
                MAX*NUM_THREADS, raceList.size(), raceCount );
    System.out.printf("Array lost %,d. Count lost %,d\n",
             MAX*NUM_THREADS-raceList.size(), MAX*NUM_THREADS-raceCount );
    }   // end RaceCondition constructor



    class RaceThread extends Thread {
    public void run() {
        for ( int i=0; i<MAX; i++){
        try {
            update( i );        
        }    // These  catches show when one thread steps on another's values
        catch( ArrayIndexOutOfBoundsException ai ){ System.out.print("A"); }
        catch( OutOfMemoryError oome ) { System.out.print("O"); }
        }
    }

    // so we don't lose counts, need to synchronize on some object, not primitive
    // Created "countLock" to show how this can work.
    // Comment out the synchronized and ending {, see that we lose counts.

//    public synchronized void update(int i){   // use A
    public void update(int i){                  // remove this when adding A
//      synchronized(countLock){            // or B
//      synchronized(this){             // or C
        raceCount = raceCount + 1;
        raceList.add( i );      // use Vector  
//          }           // end block for B or C
    }   // end update

    }   // end RaceThread inner class


} // end RaceCondition outter class
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top