Frage

In Java ist die idiomatische Art und Weise zu erklären, die kritische Abschnitte in der code ist der folgende:

private void doSomething() {
  // thread-safe code
  synchronized(this) {
    // thread-unsafe code
  }
  // thread-safe code
}

Nahezu alle Blöcke synchronisieren this, aber gibt es einen bestimmten Grund dafür?Gibt es andere Möglichkeiten?Gibt es irgendwelche best practices auf, was für ein Objekt zu synchronisieren?(wie private Instanzen Object?)

War es hilfreich?

Lösung

Beachten Sie zunächst, dass der folgende code-Schnipsel sind identisch.

public void foo() {
    synchronized (this) {
        // do something thread-safe
    }
}

und:

public synchronized void foo() {
    // do something thread-safe
}

do genau die gleiche Sache.Keine Präferenz für eines von Ihnen, außer für die Lesbarkeit des Codes und Stil.

Wenn Sie synchronisieren, Methoden oder code-Blöcke, es ist wichtig zu wissen warum Sie sind, so etwas zu tun, und was Objekt genau Sie sind sperren, und für welchen Zweck.

Beachten Sie auch, dass es Situationen gibt, in denen Sie möchten client-Seite synchronisieren code-Blöcke, in denen dem monitor, den Sie verlangen (D. H.das synchronisierte Objekt) ist nicht unbedingt this, wie in diesem Beispiel :

Vector v = getSomeGlobalVector();
synchronized (v) {
    // some thread-safe operation on the vector
}

Ich schlage vor, dass du mehr wissen über concurrent programming, es wird dienen Sie eine große deal wenn Sie genau wissen, was hinter den kulissen geschieht.Sie sollten überprüfen, Concurrent Programming in Java, ein großartiges Buch über das Thema.Wenn Sie wollen eine schnelle Tauchen Sie in das Thema, check out Java Concurrency @ Sun

Andere Tipps

Wie früher Beantworter bemerkt haben, ist es am besten Praxis, um die Synchronisierung auf ein Objekt des begrenzten Umfangs (in anderen Worten, wählen Sie die meisten restriktiven Bereich, den Sie bekommen kann Weg mit, und verwenden Sie diese.) Insbesondere das synchronisieren auf this eine schlechte Idee, es sei denn, Sie beabsichtigen, erlauben die Benutzer Ihrer Klasse zu gewinnen, das Schloss.

Ein besonders hässlichen Fall, obwohl, wenn Sie wählen, um zu synchronisieren java.lang.String.Strings werden kann (und in der Praxis fast immer der Fall ist) interniert.Das bedeutet, dass jeder string von gleicher Inhalt - in der GESAMTE JVM - stellt sich heraus, dass die gleiche Zeichenfolge hinter den kulissen.Das bedeutet, dass wenn Sie die Synchronisierung auf einem beliebigen String, eine andere (völlig unterschiedlichen) code-Abschnitt, der sperrt auch auf einen String mit dem gleichen Inhalt, tatsächlich sperren code.

Ich war mal Fehlerbehebung bei einem deadlock in einer Produktion system und (sehr schmerzhaft) verfolgt den deadlock zu zwei völlig unterschiedlichen open-source-Pakete, die jedem synchronisiert, der auf eine Instanz von String, dessen Inhalt waren beide "LOCK".

Ich versuche zu vermeiden, synchronisieren auf this denn das würde anderen erlauben, von außen, der hatte einen Verweis auf das Objekt zu block meine Synchronisation.Stattdessen erstelle ich eine lokale Synchronisierung-Objekts:

public class Foo {
    private final Object syncObject = new Object();
    …
}

Jetzt kann ich mit, dass das Objekt für die Synchronisierung ohne Angst vor niemandem "stehlen" die Sperre.

Nur um zu verdeutlichen, dass es auch ReadWriteLocks in Java, as found java.util.Auger.sperren.ReadWriteLock.

In den meisten meiner Nutzung habe ich separate mein sperren "zum Lesen' und 'updates'.Wenn Sie verwenden einfach eine synchronized-Schlüsselwort, alle liest der gleichen Methode/code-block 'in Warteschlange'.Nur ein thread kann auf die block zu einer Zeit.

In den meisten Fällen, Sie nie haben zu sorgen über die Parallelität von Problemen, wenn Sie sind einfach etwas zu Lesen.Es ist, wenn Sie schreiben, dass Sie sich sorgen über concurrent updates (was zum Verlust von Daten), oder beim Lesen, beim schreiben (Teil-updates), dass man Angst haben muss.

Daher ist eine lese - /Schreibsperre macht mehr Sinn für mich, während multi-Thread-Programmierung.

Sie synchronisieren möchten, auf ein Objekt dienen kann, wie ein Mutex.Wenn die aktuelle Instanz (die diese Referenz geeignet ist (kein Singleton ist, zum Beispiel), Sie können es verwenden, wie in Java jedes Objekt dienen kann, wie der Mutex.

In anderen Fällen möchten Sie möglicherweise die Freigabe eines Mutex zwischen mehreren Klassen, wenn Instanzen dieser Klassen können alle greifen auf die gleichen Ressourcen.

Es hängt viel von der Umgebung in der Sie arbeiten, und der Art des Systems, das Sie erstellen.In den meisten Java-EE-Anwendungen, die ich gesehen habe, gibt es eigentlich keine wirkliche Notwendigkeit für die Synchronisierung...

Ich persönlich glaube, dass die Antworten, die darauf bestehen, dass es nie oder nur selten richtig synchronisieren this Sie fehlgeleitet sind.Ich denke, es hängt von Ihrer API.Wenn Ihre Klasse ein threadsicher Umsetzung und Sie so dokumentieren, dann sollten Sie this.Wenn die Synchronisierung nicht machen jede Instanz der Klasse als ganzes threadsicher in der Anrufung der öffentlichen Methoden, dann sollten Sie eine private interne Objekt.Wiederverwendbare Bibliothek-Komponenten oft fällt in die ehemalige Kategorie - Sie müssen sorgfältig denken, bevor Sie nicht zulassen, dass der Benutzer zu wickeln Sie Ihre API in der externen Synchronisation.

Im ersten Fall, mit this ermöglicht mehrere Methoden, die aufgerufen werden soll, in eine Atomare Weise.Ein Beispiel ist PrintWriter, wo Sie wollen, um die Ausgabe mehrerer Zeilen (sagen wir einen stack-trace, um die Konsole/logger) und Garantie, die Sie zusammen angezeigt - in diesem Fall die Tatsache, dass es verbirgt das sync-Objekt ist ein echter Schmerz.Ein anderes Beispiel sind die synchronisierten Sammlung Wrapper - da müssen Sie die Synchronisierung auf das collection-Objekt selbst, um zu iterieren;da die iteration besteht aus mehreren Methodenaufrufen Sie nicht schützen Sie es vollständig intern.

Im letzteren Fall habe ich mit einem einfachen Objekt:

private Object mutex=new Object();

Allerdings haben viele gesehen, die JVM-dumps und stack-traces, die sagen, eine Sperre ist "eine Instanz von java.lang.Object()" muss ich sagen, dass die Verwendung einer inneren Klasse kann oft hilfreicher sein, wie andere vorgeschlagen haben.

Das ist sowieso meine zwei bits Wert.

Edit:Eine andere Sache, wenn die Synchronisierung auf this Ich bevorzuge zum synchronisieren der Methoden, und halten Sie die Methoden sehr körnig ist.Ich denke, es ist klarer und mehr prägnant.

Synchronisation in Java beinhaltet Häufig die Synchronisierung von Operationen auf der gleichen Instanz.Synchronisierung auf this dann ist sehr idiomatisch, da this ist eine gemeinsame Referenz, die automatisch zwischen verschiedenen Instanz-Methoden (oder-Abschnitte) in eine Klasse.

Mit einem anderen Verweis speziell für die Verriegelung, indem Sie die Deklaration und Initialisierung einer privaten Feld Object lock = new Object() für Beispiel, ist etwas, was ich nie gebraucht oder benutzt.Ich denke, es ist nur nützlich, wenn Sie benötigen externe Synchronisierung auf zwei oder mehrere nicht synchronisierte Ressourcen in einem Objekt, aber ich würde immer versuchen, umgestalten, eine solche situation in eine einfachere form.

Sowieso, implizite (synchronisierte Methode) oder explizit synchronized(this) ist eine Menge verwendet, auch in der Java-Bibliotheken.Es ist eine gute Bildsprache und, falls zutreffend, sollte immer Ihre erste Wahl sein.

Auf was Sie synchronisieren, hängt davon ab, was andere threads, die möglicherweise in Konflikt kommen mit dieser Methode rufen Sie eine Synchronisierung durchführen können.

Wenn this ist ein Objekt, das nur von einem thread und wir sind auf ein veränderliches Objekt zwischen threads gemeinsam genutzt werden, ein guter Kandidat ist, um die Synchronisierung über das Objekt - Synchronisierung auf this hat keinen Sinn, da ein anderer thread, der ändert, dass das gemeinsame Objekt möglicherweise nicht einmal wissen, this, aber nicht wissen, dass Objekt.

Auf der anderen Seite synchronisieren über this macht Sinn, wenn viele threads rufen Methoden dieses Objekts zur gleichen Zeit, zum Beispiel, wenn wir sind in ein singleton.

Beachten Sie, dass die synchronen Methode ist oft nicht die beste option, da wir die Sperre die ganze Zeit die Methode ausgeführt wird.Wenn es enthält zeitaufwändig, aber thread-sicheren teilen, und nicht so zeitaufwendig thread-unsafe-Teil, das synchronisieren über die Methode ist sehr falsch.

Nahezu alle Blöcke synchronisieren, aber gibt es einen bestimmten Grund dafür?Gibt es andere Möglichkeiten?

Diese Erklärung synchronisiert die gesamte Methode.

private synchronized void doSomething() {

Diese Erklärung synchronisiert wird ein Teil des code-Blocks, statt der gesamten Methode.

private void doSomething() {
  // thread-safe code
  synchronized(this) {
    // thread-unsafe code
  }
  // thread-safe code
}

Aus der oracle-Dokumentation Seite

machen Sie diese Methoden synchronisiert hat zwei Effekte:

Erstens ist es nicht möglich, dass zwei Aufrufe synchronisierter Methoden auf dasselbe Objekt interleave.Wenn ein thread eine synchronisierte Methode für ein Objekt, werden alle anderen threads aufrufen, die synchronisierte Methoden für dasselbe Objekt block (suspend Ausführung), bis der erste thread fertig ist mit dem Objekt.

Gibt es andere Möglichkeiten?Gibt es irgendwelche best practices auf, was für ein Objekt zu synchronisieren?(wie private Instanzen des Objekts?)

Es gibt viele Möglichkeiten und alternativen, um die Synchronisierung.Ihr code threadsicher ist mit der high-level-Parallelität APIs( seit JDK 1.5 release)

Lock objects
Executors
Concurrent collections
Atomic variables
ThreadLocalRandom

Siehe unten SE Fragen für mehr details:

Synchronisation vs Lock

Vermeiden synchronisiert(this) in Java?

das Beste Verfahren ist, um ein Objekt erstellen, das ausschließlich die Sperre:

private final Object lock = new Object();

private void doSomething() {
  // thread-safe code
  synchronized(lock) {
    // thread-unsafe code
  }
  // thread-safe code
}

Dadurch sind Sie sicher, dass keine aufrufende code kann je deadlock Ihre Methode, indem Sie eine unbeabsichtigte synchronized(yourObject) Linie.

(Credits an @jared und @yuval-adam, erklärte, das in weitere details über.)

Meine Vermutung ist, dass die Beliebtheit der Nutzung this in tutorials kam von der frühen Sun javadoc: https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top