Was bedeutet "synchronisiert"?


993

Ich habe einige Fragen zur Verwendung und Bedeutung des synchronizedSchlüsselworts.

  • Welche Bedeutung hat das synchronizedSchlüsselwort?
  • Wann sollten Methoden sein synchronized?
  • Was bedeutet es programmatisch und logisch?


1
hilfreiche Diskussion zwischen Hashmap und Hashtable und Synchronisation: stackoverflow.com/questions/40471/java-hashmap-vs-hashtable
limc


1
Ich habe den gesamten Dokumentationslink vom ersten Kommentar an durchgesehen und erst verstanden, als ich zum letzten Absatz kam. Anstatt Links einzufügen und nichts zu zitieren, ist es möglicherweise hilfreicher, Links einzufügen und ein Zitat hinzuzufügen.
Rakib

Antworten:


878

Das synchronizedSchlüsselwort handelt von verschiedenen Threads, die in dieselben Variablen, Objekte und Ressourcen lesen und schreiben. Dies ist kein triviales Thema in Java, aber hier ist ein Zitat von Sun:

synchronized Methoden ermöglichen eine einfache Strategie zur Vermeidung von Thread-Interferenzen und Speicherkonsistenzfehlern: Wenn ein Objekt für mehr als einen Thread sichtbar ist, werden alle Lese- oder Schreibvorgänge in die Variablen dieses Objekts über synchronisierte Methoden ausgeführt.

Kurz gesagt: Wenn Sie zwei Threads haben, die in derselben 'Ressource' lesen und schreiben, beispielsweise eine Variable mit dem Namen foo, müssen Sie sicherstellen, dass diese Threads auf atomare Weise auf die Variable zugreifen. Ohne das synchronizedSchlüsselwort sieht Ihr Thread 1 möglicherweise nicht, dass der Änderungsthread 2 vorgenommen wurde foo, oder schlimmer noch, er wird möglicherweise nur zur Hälfte geändert. Dies ist nicht das, was Sie logischerweise erwarten.

Auch dies ist in Java ein nicht triviales Thema. Weitere Informationen finden Sie hier auf SO und in den Interwebs zu folgenden Themen:

Erforschen Sie diese Themen so lange, bis der Name "Brian Goetz" dauerhaft mit dem Begriff "Parallelität" in Ihrem Gehirn in Verbindung gebracht wird.


71
Im Grunde genommen macht dieses synchronisierte Schlüsselwort Ihre Methoden threadsicher?
Rigo Vides

82
Das synchronisierte Schlüsselwort ist eines der Tools, die Ihren Code-Thread sicher machen. Nur die Verwendung von synchronisiert für eine Methode oder Variable an sich kann den Trick tun oder auch nicht. Ein grundlegendes Verständnis des Java-Speichermodells ist wirklich wichtig, um die Parallelität zu korrigieren.
Stu Thompson

28
Wenn Sie nicht Brian Goetz (oder vielleicht Jon Skeet) sind, ist es fast unmöglich, die Java-Parallelität nur mit den Sprachprimitiven (synchronisiert, flüchtig) korrekt zu machen. Verwenden Sie zunächst das Paket java.util.concurrent und bauen Sie darauf auf.
Thilo

12
Noch deutlicher: Synchronisierte Methoden können nicht gleichzeitig von mehreren Threads aufgerufen werden.
Peter

2
@ Peterh synchronisiert macht mehr als das, daher die ausführlichere Erklärung
Stu Thompson

293

Nun, ich denke, wir hatten genug theoretische Erklärungen, also denken Sie an diesen Code

public class SOP {
    public static void print(String s) {
        System.out.println(s+"\n");
    }
}

public class TestThread extends Thread {
    String name;
    TheDemo theDemo;
    public TestThread(String name,TheDemo theDemo) {
        this.theDemo = theDemo;
        this.name = name;
        start();
    }
    @Override
    public void run() {
        theDemo.test(name);
    }
}

public class TheDemo {
    public synchronized void test(String name) {
        for(int i=0;i<10;i++) {
            SOP.print(name + " :: "+i);
            try{
                Thread.sleep(500);
            } catch (Exception e) {
                SOP.print(e.getMessage());
            }
        }
    }
    public static void main(String[] args) {
        TheDemo theDemo = new TheDemo();
        new TestThread("THREAD 1",theDemo);
        new TestThread("THREAD 2",theDemo);
        new TestThread("THREAD 3",theDemo);
    }
}

Hinweis: synchronizedBlockiert den Aufruf des nächsten Threads an method test (), solange die Ausführung des vorherigen Threads nicht abgeschlossen ist. Threads können einzeln auf diese Methode zugreifen. Ohne synchronizedalle Threads kann gleichzeitig auf diese Methode zugegriffen werden.

Wenn ein Thread die synchronisierte Methode 'test' des Objekts aufruft (hier ist das Objekt eine Instanz der 'TheDemo'-Klasse), erhält er die Sperre dieses Objekts. Ein neuer Thread kann KEINE synchronisierte Methode desselben Objekts aufrufen, solange der vorherige Thread Wer das Schloss erworben hat, gibt das Schloss nicht frei.

Ähnliches passiert, wenn eine statisch synchronisierte Methode der Klasse aufgerufen wird. Der Thread erhält die der Klasse zugeordnete Sperre (in diesem Fall kann jede nicht statische synchronisierte Methode einer Instanz dieser Klasse von jedem Thread aufgerufen werden, da diese Sperre auf Objektebene noch verfügbar ist). Ein anderer Thread kann keine statisch synchronisierte Methode der Klasse aufrufen, solange die Sperre auf Klassenebene nicht von dem Thread freigegeben wird, der derzeit die Sperre enthält.

Ausgabe mit synchronisiert

THREAD 1 :: 0
THREAD 1 :: 1
THREAD 1 :: 2
THREAD 1 :: 3
THREAD 1 :: 4
THREAD 1 :: 5
THREAD 1 :: 6
THREAD 1 :: 7
THREAD 1 :: 8
THREAD 1 :: 9
THREAD 3 :: 0
THREAD 3 :: 1
THREAD 3 :: 2
THREAD 3 :: 3
THREAD 3 :: 4
THREAD 3 :: 5
THREAD 3 :: 6
THREAD 3 :: 7
THREAD 3 :: 8
THREAD 3 :: 9
THREAD 2 :: 0
THREAD 2 :: 1
THREAD 2 :: 2
THREAD 2 :: 3
THREAD 2 :: 4
THREAD 2 :: 5
THREAD 2 :: 6
THREAD 2 :: 7
THREAD 2 :: 8
THREAD 2 :: 9

Ausgabe ohne synchronisiert

THREAD 1 :: 0
THREAD 2 :: 0
THREAD 3 :: 0
THREAD 1 :: 1
THREAD 2 :: 1
THREAD 3 :: 1
THREAD 1 :: 2
THREAD 2 :: 2
THREAD 3 :: 2
THREAD 1 :: 3
THREAD 2 :: 3
THREAD 3 :: 3
THREAD 1 :: 4
THREAD 2 :: 4
THREAD 3 :: 4
THREAD 1 :: 5
THREAD 2 :: 5
THREAD 3 :: 5
THREAD 1 :: 6
THREAD 2 :: 6
THREAD 3 :: 6
THREAD 1 :: 7
THREAD 2 :: 7
THREAD 3 :: 7
THREAD 1 :: 8
THREAD 2 :: 8
THREAD 3 :: 8
THREAD 1 :: 9
THREAD 2 :: 9
THREAD 3 :: 9

7
Tolles Beispiel, es ist gut, die Theorie zu kennen, aber der Code ist immer spezifischer und vollständiger.
Santi Iglesias

2
@ SantiIglesias "Vollständig"? Nee. Dieses Beispiel zeigt das Sperrverhalten von synchronized, aber die Speicherkonsistenz wird ignoriert.
Stu Thompson

2
@ Stu Thompson Speicherkonsistenz ist das Ergebnis der Sperrung
Dheeraj Sachan

@DheerajSachan Nach dieser Logik würde die Verwendung eines ReentrantLock zu einer Speicherkonsistenz führen. Das tut es nicht.
Stu Thompson

3
@boltup_im_coding: Die Methode start () versetzt den Thread in den Status "RUNNABLE", was bedeutet, dass er zur Ausführung bereit ist oder bereits ausgeführt wird. Es kann vorkommen, dass ein anderer Thread (normalerweise, aber nicht unbedingt mit höherer Priorität) im Status "Ausführbar" die Warteschlange überspringt und mit der Ausführung beginnt. Im obigen Beispiel hat THREAD 3 zufällig CPU vor THREAD 2 erhalten.
Sahil J

116

Das synchronizedSchlüsselwort verhindert den gleichzeitigen Zugriff mehrerer Threads auf einen Code- oder Objektblock. Alle Methoden von Hashtableare synchronizedsind so, dass jeweils nur ein Thread sie ausführen kann.

Wenn Sie Nicht- synchronizedKonstrukte wie verwenden HashMap, müssen Sie Thread-Sicherheitsfunktionen in Ihrem Code erstellen, um Konsistenzfehler zu vermeiden.


81

synchronizedbedeutet, dass in einer Umgebung mit mehreren Threads ein Objekt mit synchronizedMethode (n) / Block (en) nicht zwei Threads gleichzeitig auf die synchronizedMethode (n) / Block (e) des Codes zugreifen lässt . Dies bedeutet, dass ein Thread nicht lesen kann, während ein anderer Thread ihn aktualisiert.

Der zweite Thread wartet stattdessen, bis der erste Thread seine Ausführung abgeschlossen hat. Der Overhead ist die Geschwindigkeit, aber der Vorteil ist die garantierte Datenkonsistenz.

Wenn Ihre Anwendung jedoch Single-Threaded ist, synchronizedbieten Blöcke keine Vorteile.


54

Das synchronizedSchlüsselwort bewirkt, dass ein Thread bei der Eingabe der Methode eine Sperre erhält, sodass nur ein Thread die Methode gleichzeitig ausführen kann (für die angegebene Objektinstanz, sofern es sich nicht um eine statische Methode handelt).

Dies wird häufig als Thread-sicher bezeichnet, aber ich würde sagen, dass dies ein Euphemismus ist. Zwar schützt die Synchronisierung den internen Status des Vektors vor Beschädigung, dies hilft dem Benutzer von Vector jedoch normalerweise nicht viel.

Bedenken Sie:

 if (vector.isEmpty()){
     vector.add(data);
 }

Obwohl die beteiligten Methoden synchronisiert sind, weil sie einzeln gesperrt und entsperrt werden, können zwei leider zeitgesteuerte Threads einen Vektor mit zwei Elementen erstellen.

Tatsächlich müssen Sie also auch Ihren Anwendungscode synchronisieren.

Da die Synchronisation auf Methodenebene a) teuer ist, wenn Sie sie nicht benötigen, und b) unzureichend ist, wenn Sie eine Synchronisation benötigen, gibt es jetzt nicht synchronisierte Ersetzungen (ArrayList im Fall von Vector).

In jüngerer Zeit wurde das Parallelitätspaket mit einer Reihe cleverer Dienstprogramme veröffentlicht, die sich um Multithreading-Probleme kümmern.


26

Überblick

Das synchronisierte Schlüsselwort in Java hat mit der Thread-Sicherheit zu tun, dh wenn mehrere Threads dieselbe Variable lesen oder schreiben.
Dies kann direkt (durch Zugriff auf dieselbe Variable) oder indirekt (durch Verwendung einer Klasse, die eine andere Klasse verwendet, die auf dieselbe Variable zugreift) geschehen.

Das synchronisierte Schlüsselwort wird verwendet, um einen Codeblock zu definieren, in dem mehrere Threads auf sichere Weise auf dieselbe Variable zugreifen können.

Tiefer

In Bezug auf die Syntax synchronizednimmt das Schlüsselwort a Objectals Parameter (als Sperrobjekt bezeichnet ) an, gefolgt von a { block of code }.

  • Wenn die Ausführung dieses Schlüsselwort trifft, der aktuelle Thread versucht, „lock / acquire / eigenen“ (nehmen Sie Ihre Wahl) , um das Sperrobjekt hat und führen Sie den zugehörigen Code - Block , nachdem die Sperre erworben.

  • Alle Schreibvorgänge in Variablen innerhalb des synchronisierten Codeblocks sind garantiert für jeden anderen Thread sichtbar, der Code in einem synchronisierten Codeblock mit demselben Sperrobjekt auf ähnliche Weise ausführt .

  • Es kann jeweils nur ein Thread die Sperre halten. Während dieser Zeit warten alle anderen Threads, die versuchen, dasselbe Sperrobjekt zu erhalten , (halten ihre Ausführung an). Die Sperre wird aufgehoben, wenn die Ausführung den synchronisierten Codeblock verlässt.

Synchronisierte Methoden:

Hinzufügen synchronizedSchlüsselwort zu einer Methodendefinition ist gleich den gesamte Verfahren Körper in einem synchronisierten Codeblock mit eingewickelt Sperrobjekt Wesen this (beispielsweise Methoden) und ClassInQuestion.getClass() (für Klassenmethoden) .

- Die Instanzmethode ist eine Methode ohne staticSchlüsselwort.
- Die Klassenmethode ist eine Methode mit einem staticSchlüsselwort.

Technisch

Ohne Synchronisation kann nicht garantiert werden, in welcher Reihenfolge die Lese- und Schreibvorgänge stattfinden, wodurch möglicherweise die Variable mit Müll belassen wird.
(Zum Beispiel könnte eine Variable die Hälfte der von einem Thread geschriebenen Bits und die Hälfte der von einem anderen Thread geschriebenen Bits enthalten, wodurch die Variable in einem Zustand verbleibt, den keiner der Threads zu schreiben versucht hat, sondern ein kombiniertes Durcheinander von beiden.)

Es reicht nicht aus, einen Schreibvorgang in einem Thread abzuschließen, bevor (Wanduhrzeit) ein anderer Thread ihn liest, da die Hardware den Wert der Variablen zwischengespeichert haben könnte und der Lesethread den zwischengespeicherten Wert anstelle dessen sehen würde, in den geschrieben wurde es.

Fazit

In Javas Fall müssen Sie daher dem Java-Speichermodell folgen, um sicherzustellen, dass keine Threading-Fehler auftreten.
Mit anderen Worten: Verwenden Sie Synchronisation, atomare Operationen oder Klassen, die sie für Sie unter der Haube verwenden.

Quellen

http://docs.oracle.com/javase/specs/jls/se8/html/index.html
Java®-Sprachspezifikation, 13.02.2015


Entschuldigung, aber ich habe dieses Beispiel und verstehe die Bedeutung nicht: `Integer i1 = Arrays.asList (1,2,3,4,5) .stream (). FindAny (). Get (); synchronized (i1) {Integer i2 = Arrays.asList (6,7,8,9,10) .parallelStream () .sorted () .findAny (). get (); System.out.println (i1 + "" + i2); } `1. Warum haben Sie den Block bei der ersten Instanz aufgerufen und dieser Aufruf hat keine Auswirkung auf den Code? 2. Die zweite Instanz ist trotz des Aufrufs des Blocks auf der ersten Thread-sicher?
Adryr83

1
@ Adryr83 Wenn Sie eine Frage haben, können Sie diese wahrscheinlich stellen, indem Sie eine neue Frage stellen. Aber da wir hier sind, werde ich analysieren, was ich kann (Ihre Frage ist etwas schwer zu verstehen). Nach allem, was ich über diesen Code sagen kann, scheint er nichts zu enthalten, was eine Synchronisation erfordert. Es ist aus dem Zusammenhang geraten. Vorschlag: Wenn Sie können, versuchen Sie, den Code in kleinere Einzelstücke aufzuteilen, und suchen Sie dann nach Antworten zu diesen. Es ist viel einfacher, kleine und isolierte Probleme zu verstehen, als einen großen Codeblock herauszufinden.
Gima

21

Stellen Sie sich das als eine Art Drehkreuz vor, wie Sie es auf einem Fußballplatz finden könnten. Es gibt parallele Dämpfe von Menschen, die einsteigen wollen, aber am Drehkreuz sind sie "synchronisiert". Es kann immer nur eine Person durchkommen. Alle, die durchkommen wollen, werden es tun, aber sie müssen möglicherweise warten, bis sie durchkommen können.


16

Was ist das synchronisierte Schlüsselwort?

Threads kommunizieren hauptsächlich durch gemeinsame Nutzung des Zugriffs auf Felder und die Objekte, auf die sich Referenzfelder beziehen. Diese Form der Kommunikation ist äußerst effizient, ermöglicht jedoch zwei Arten von Fehlern: Thread-Interferenz und Speicherkonsistenzfehler . Das zur Vermeidung dieser Fehler erforderliche Tool ist die Synchronisation.

Synchronisierte Blöcke oder Methoden verhindern Thread-Interferenzen und stellen sicher, dass die Daten konsistent sind. Zu jedem Zeitpunkt kann nur ein Thread auf einen synchronisierten Block oder eine synchronisierte Methode ( kritischer Abschnitt ) zugreifen, indem er eine Sperre erwirbt. Andere Threads warten auf die Freigabe der Sperre, um auf den kritischen Abschnitt zuzugreifen .

Wann werden Methoden synchronisiert?

Methoden werden synchronisiert, wenn Sie sie synchronizedzur Methodendefinition oder -deklaration hinzufügen . Sie können einen bestimmten Codeblock auch mit einer Methode synchronisieren.

Was bedeutet es programmatisch und logisch?

Dies bedeutet, dass nur ein Thread durch Erwerb einer Sperre auf einen kritischen Abschnitt zugreifen kann . Sofern dieser Thread diese Sperre nicht aufhebt, müssen alle anderen Threads warten, um eine Sperre zu erhalten. Sie haben keinen Zugriff auf den kritischen Bereich , ohne eine Sperre zu erhalten.

Dies kann nicht mit Magie geschehen. Es liegt in der Verantwortung des Programmierers, kritische Abschnitte in der Anwendung zu identifizieren und entsprechend zu schützen. Java bietet ein Framework zum Schutz Ihrer Anwendung, aber wo und was alle zu schützenden Abschnitte sind, liegt in der Verantwortung des Programmierers.

Weitere Details von Java - Dokumentation Seite

Eigensperren und Synchronisation:

Die Synchronisierung basiert auf einer internen Entität, die als intrinsische Sperre oder Monitorsperre bezeichnet wird. Intrinsische Sperren spielen in beiden Aspekten der Synchronisation eine Rolle: Erzwingen des exklusiven Zugriffs auf den Status eines Objekts und Herstellen von Vor-Vor-Beziehungen, die für die Sichtbarkeit wesentlich sind.

Jedem Objekt ist eine intrinsische Sperre zugeordnet . Gemäß der Konvention muss ein Thread, der exklusiven und konsistenten Zugriff auf die Felder eines Objekts benötigt, die intrinsische Sperre des Objekts abrufen, bevor er auf sie zugreift, und dann die intrinsische Sperre aufheben, wenn sie damit fertig ist.

Ein Thread soll die intrinsische Sperre zwischen dem Zeitpunkt, zu dem er die Sperre erworben und die Sperre freigegeben hat, besitzen. Solange ein Thread eine intrinsische Sperre besitzt, kann kein anderer Thread dieselbe Sperre erhalten. Der andere Thread wird blockiert, wenn er versucht, die Sperre zu erlangen.

Wenn ein Thread eine intrinsische Sperre aufhebt, wird eine Beziehung zwischen dieser Aktion und jeder nachfolgenden Erfassung derselben Sperre hergestellt.

Das Synchronisieren von Methoden hat zwei Auswirkungen :

Erstens ist es nicht möglich, dass zwei Aufrufe synchronisierter Methoden für dasselbe Objekt verschachtelt werden.

Wenn ein Thread eine synchronisierte Methode für ein Objekt ausführt, blockieren alle anderen Threads, die synchronisierte Methoden für denselben Objektblock aufrufen (Ausführung aussetzen), bis der erste Thread mit dem Objekt fertig ist.

Zweitens wird beim Beenden einer synchronisierten Methode automatisch eine Vorher-Beziehung zu einem nachfolgenden Aufruf einer synchronisierten Methode für dasselbe Objekt hergestellt.

Dies garantiert, dass Änderungen am Status des Objekts für alle Threads sichtbar sind.

Suchen Sie nach anderen Alternativen zur Synchronisation in:

Vermeiden Sie (dies) in Java synchronisiert?


11

Synchronized normal methodäquivalent zu Synchronized statement(benutze dies)

class A {
    public synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(this) {
             // all function code
        }
    } 
}

Synchronized static methodäquivalent zu Synchronized statement(Klasse verwenden)

class A {
    public static synchronized void methodA() {
        // all function code
    }

    equivalent to

    public void methodA() {
        synchronized(A.class) {
             // all function code
        }
    } 
}

Synchronisierte Anweisung (unter Verwendung einer Variablen)

class A {
    private Object lock1 = new Object();

    public void methodA() {
        synchronized(lock1 ) {
             // all function code
        }
    } 
}

Denn synchronizedwir haben beide Synchronized Methodsund Synchronized Statements. Ist Synchronized Methodsjedoch ähnlich, Synchronized Statementsso müssen wir nur verstehen Synchronized Statements.

=> Grundsätzlich werden wir haben

synchronized(object or class) { // object/class use to provides the intrinsic lock
   // code 
}

Hier sind 2 Gedanken, die zum Verständnis beitragen synchronized

  • Jedem Objekt / jeder Klasse ist ein Objekt intrinsic lockzugeordnet.
  • Wenn ein Thread a aufruft synchronized statement, erfasst er automatisch das intrinsic lockfür dieses synchronized statement'sObjekt und gibt es frei, wenn die Methode zurückkehrt. Solange ein Thread einen besitzt intrinsic lock, kann KEIN anderer Thread die gleiche Sperre erhalten => threadsicher.

=> Wenn ein thread AAufruf synchronized(this){// code 1}=> ist der gesamte Blockcode (innerhalb der Klasse) wo synchronized(this)und alle synchronized normal method(innerhalb der Klasse) wegen der gleichen Sperre gesperrt . Es wird nach dem thread AEntsperren ausgeführt ("// Code 1" beendet).

Dieses Verhalten ähnelt synchronized(a variable){// code 1}oder synchronized(class).

SAME LOCK => lock (nicht abhängig von welcher Methode? Oder welchen Anweisungen?)

Synchronisierte Methode oder synchronisierte Anweisungen verwenden?

Ich bevorzuge, synchronized statementsweil es erweiterbarer ist. In Zukunft müssen Sie beispielsweise nur einen Teil der Methode synchronisieren. Beispiel: Sie haben zwei synchronisierte Methoden, die für einander nicht relevant sind. Wenn ein Thread jedoch eine Methode ausführt, blockiert er die andere Methode (dies kann durch Verwendung verhindert werden synchronized(a variable)).

Das Anwenden der synchronisierten Methode ist jedoch einfach und der Code sieht einfach aus. Für einige Klassen gibt es nur eine synchronisierte Methode oder alle synchronisierten Methoden in der Klasse, die für einander relevant sind => Wir können synchronized methodden Code kürzer und verständlicher machen

Hinweis

(es ist nicht zu relevant für viel synchronized, es ist der Unterschied zwischen Objekt und Klasse oder nicht statisch und statisch).

  • Wenn Sie synchronizedoder normale Methode oder synchronized(this)oder synchronized(non-static variable)Base auf jeder Objektinstanz wird es synchronisiert.
  • Wenn Sie eine synchronizedstatische Methode verwenden oder synchronized(class)oder synchronized(static variable)sie wird basierend auf der Klasse synchronisiert

Referenz

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

Hoffe es hilft


11

Hier ist eine Erklärung aus den Java-Tutorials .

Betrachten Sie den folgenden Code:

public class SynchronizedCounter {
    private int c = 0;

    public synchronized void increment() {
        c++;
    }

    public synchronized void decrement() {
        c--;
    }

    public synchronized int value() {
        return c;
    }
}

Wenn dies counteine Instanz von ist SynchronizedCounter, hat das Synchronisieren dieser Methoden zwei Auswirkungen:

  • Erstens ist es nicht möglich, dass zwei Aufrufe synchronisierter Methoden für dasselbe Objekt verschachtelt werden. Wenn ein Thread eine synchronisierte Methode für ein Objekt ausführt, blockieren alle anderen Threads, die synchronisierte Methoden für denselben Objektblock aufrufen (Ausführung aussetzen), bis der erste Thread mit dem Objekt fertig ist.
  • Zweitens wird beim Beenden einer synchronisierten Methode automatisch eine Vorher-Beziehung zu einem nachfolgenden Aufruf einer synchronisierten Methode für dasselbe Objekt hergestellt. Dies garantiert, dass Änderungen am Status des Objekts für alle Threads sichtbar sind.

9

Nach meinem Verständnis bedeutet synchronisiert im Grunde, dass der Compiler eine monitor.enter und eine monitor.exit um Ihre Methode schreibt. Als solches kann es threadsicher sein, abhängig davon, wie es verwendet wird (ich meine, Sie können ein Objekt mit synchronisierten Methoden schreiben, das nicht threadsicher ist, abhängig davon, was Ihre Klasse tut).


5

Was den anderen Antworten fehlt, ist ein wichtiger Aspekt: Gedächtnisbarrieren . Die Thread-Synchronisation besteht im Wesentlichen aus zwei Teilen: Serialisierung und Sichtbarkeit. Ich rate jedem, nach "jvm memory barriere" zu googeln, da dies ein nicht triviales und äußerst wichtiges Thema ist (wenn Sie gemeinsam genutzte Daten ändern, auf die mehrere Threads zugreifen). Nachdem dies geschehen ist, empfehle ich, die Klassen des Pakets java.util.concurrent zu betrachten, um die Verwendung einer expliziten Synchronisierung zu vermeiden, was wiederum dazu beiträgt, Programme einfach und effizient zu halten und möglicherweise sogar Deadlocks zu verhindern.

Ein solches Beispiel ist ConcurrentLinkedDeque . Zusammen mit dem Befehlsmuster können hocheffiziente Arbeitsthreads erstellt werden, indem die Befehle in die gleichzeitige Warteschlange eingefügt werden - keine explizite Synchronisierung erforderlich, keine Deadlocks möglich, kein expliziter sleep () erforderlich, einfach die Warteschlange durch Aufrufen von take () abfragen.

Kurz gesagt: "Speichersynchronisation" geschieht implizit, wenn Sie einen Thread starten, ein Thread endet, Sie eine flüchtige Variable lesen, einen Monitor entsperren (einen synchronisierten Block / eine synchronisierte Funktion verlassen) usw. Diese "Synchronisation" wirkt sich (in gewissem Sinne "auf" Flushes "aus ") alle Schreibvorgänge, die vor dieser bestimmten Aktion ausgeführt wurden. Im Fall der oben genannten ConcurrentLinkedDeque "sagt" die Dokumentation:

Speicherkonsistenzeffekte: Wie bei anderen gleichzeitigen Sammlungen werden Aktionen in einem Thread vor dem Platzieren eines Objekts in einer ConcurrentLinkedDeque ausgeführt , bevor Aktionen nach dem Zugriff oder Entfernen dieses Elements aus der ConcurrentLinkedDeque in einem anderen Thread ausgeführt werden.

Dieses implizite Verhalten ist ein etwas schädlicher Aspekt, da die meisten Java-Programmierer ohne viel Erfahrung aufgrund dessen nur eine Menge nehmen, wie angegeben. Und dann stolpern Sie plötzlich über diesen Thread, nachdem Java nicht das getan hat, was es in der Produktion "tun" soll, wo es eine andere Arbeitslast gibt - und es ziemlich schwierig ist, Parallelitätsprobleme zu testen.


3

Synchronisiert bedeutet einfach, dass mehrere Threads, wenn sie einem einzelnen Objekt zugeordnet sind, ein fehlerhaftes Lesen und Schreiben verhindern können, wenn für ein bestimmtes Objekt ein synchronisierter Block verwendet wird. Um Ihnen mehr Klarheit zu geben, nehmen wir ein Beispiel:

class MyRunnable implements Runnable {
    int var = 10;
    @Override
    public void run() {
        call();
    }

    public void call() {
        synchronized (this) {
            for (int i = 0; i < 4; i++) {
                var++;
                System.out.println("Current Thread " + Thread.currentThread().getName() + " var value "+var);
            }
        }
    }
}

public class MutlipleThreadsRunnable {
    public static void main(String[] args) {
        MyRunnable runnable1 = new MyRunnable();
        MyRunnable runnable2 = new MyRunnable();
        Thread t1 = new Thread(runnable1);
        t1.setName("Thread -1");
        Thread t2 = new Thread(runnable2);
        t2.setName("Thread -2");
        Thread t3 = new Thread(runnable1);
        t3.setName("Thread -3");
        t1.start();
        t2.start();
        t3.start();
    }
}

Wir haben zwei MyRunnable-Klassenobjekte erstellt: runnable1 wird für Thread 1 und Thread 3 freigegeben, und runnable2 wird nur für Thread 2 freigegeben. Wenn nun t1 und t3 ohne Synchronisation gestartet werden, wird eine PFB-Ausgabe ausgegeben, die darauf hindeutet, dass beide Threads 1 und 3 gleichzeitig den var-Wert beeinflussen, wobei var für Thread 2 einen eigenen Speicher hat.

Without Synchronized keyword

    Current Thread Thread -1 var value 11
    Current Thread Thread -2 var value 11
    Current Thread Thread -2 var value 12
    Current Thread Thread -2 var value 13
    Current Thread Thread -2 var value 14
    Current Thread Thread -1 var value 12
    Current Thread Thread -3 var value 13
    Current Thread Thread -3 var value 15
    Current Thread Thread -1 var value 14
    Current Thread Thread -1 var value 17
    Current Thread Thread -3 var value 16
    Current Thread Thread -3 var value 18

Bei Verwendung von Synchronzied wartet Thread 3 in allen Szenarien darauf, dass Thread 1 abgeschlossen ist. Es wurden zwei Sperren erworben, eine für runnable1, die von Thread 1 und Thread 3 gemeinsam genutzt wird, und eine für runnable2, die nur von Thread 2 gemeinsam genutzt wird.

Current Thread Thread -1 var value 11
Current Thread Thread -2 var value 11
Current Thread Thread -1 var value 12
Current Thread Thread -2 var value 12
Current Thread Thread -1 var value 13
Current Thread Thread -2 var value 13
Current Thread Thread -1 var value 14
Current Thread Thread -2 var value 14
Current Thread Thread -3 var value 15
Current Thread Thread -3 var value 16
Current Thread Thread -3 var value 17
Current Thread Thread -3 var value 18

Synchronisiert bedeutet noch mehr: Es hat tiefgreifende Auswirkungen auf die Speicherbarriere.
user1050755

1

Einfach synchronisiert bedeutet, dass keine zwei Threads gleichzeitig auf den Block / die Methode zugreifen können. Wenn wir sagen, dass ein Block / eine Methode einer Klasse synchronisiert ist, bedeutet dies, dass jeweils nur ein Thread auf sie zugreifen kann. Intern nimmt der Thread, der zuerst versucht, darauf zuzugreifen, eine Sperre für dieses Objekt auf. Solange diese Sperre nicht verfügbar ist, kann kein anderer Thread auf eine der synchronisierten Methoden / Blöcke dieser Instanz der Klasse zugreifen.

Beachten Sie, dass ein anderer Thread auf eine Methode desselben Objekts zugreifen kann, die nicht für die Synchronisierung definiert ist. Ein Thread kann die Sperre durch Aufrufen aufheben

Object.wait()

0

synchronizedBlock in Java ist ein Monitor im Multithreading. synchronizedBlock mit demselben Objekt / derselben Klasse kann nur von einem einzelnen Thread ausgeführt werden, alle anderen warten. Dies kann hilfreich sein race condition, wenn mehrere Threads versuchen, dieselbe Variable zu aktualisieren (der erste Schritt ist die Verwendung von volatileInfo ).

Java 5erweitert synchronizeddurch die Unterstützung von happens-before[About]

Ein Entsperren (synchronisierter Block oder Methodenausgang) eines Monitors erfolgt vor jeder nachfolgenden Sperre (synchronisierter Block oder Methodeneintrag) desselben Monitors.

Der nächste Schritt ist java.util.concurrent

flüchtig vs synchronisiert


-6

synchronisiert ist ein Schlüsselwort in Java, das verwendet wird, um vor einer Beziehung in einer Multithreading-Umgebung zu geschehen, um Speicherinkonsistenzen und Thread-Interferenzfehler zu vermeiden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.