Syncchronisierung in Java

Was ist Syncchronisierung in Java?

In Java, Synchronisierung bezieht sich auf die Fähigkeit, den Zugriff mehrerer Threads auf eine gemeinsam genutzte Ressource zu steuern. Dies ist eine ideale Option, wenn wir nur einem Thread den Zugriff auf die gemeinsam genutzte Ressource erlauben möchten.

Dieser Ausführungsansatz wird normalerweise als „asynchrone“ Programmierung bezeichnet. Auf diesen Prozessoren gibt es auch Threads, also leichte Prozesse, die Anweisungen gleichzeitig ausführen können.

Arten von SyncHronisierung

Es gibt zwei Arten von Synchronisationsmethoden in Java:

1) Prozesssynchronisation

2) Thread-Synchronisierung.

Lasst uns Thread und studieren Prozesssynchronisation im Detail.

Prozesssynchronisation: Es verwaltet die Synchronisierung zwischen Programmen. Beispielsweise Programme wie `Microsoft Word` und `Acrobat Reader` laufen als einzelne Prozesse.

Thread-Synchronisierung: Die gleichzeitige Ausführung der kritischen Ressource durch zwei oder mehr Threads wird als Thread bezeichnet SyncThronisierung. Sie können weiter in „sich gegenseitig ausschließende“ und „Inter-Thread-Kommunikation“ gruppiert werden.

Was ist Lock in Java?

Einschließen Java ist um eine interne Entität herum aufgebaut, die als Monitor oder Sperre bezeichnet wird. Alle Objekte sind mit einer Sperre verknüpft. Der Thread, der konsistenten Zugriff auf die Felder eines Objekts benötigt, muss daher die Sperre des Objekts erwerben, bevor er darauf zugreift, und die Sperre freigeben, wenn die Arbeit abgeschlossen ist. Dadurch wird sichergestellt, dass immer nur ein Thread auf die gemeinsam genutzten Daten zugreift.

Multithread-Programm mit Synchronisierung

Ein Multithread-Programm ist eine Methode oder ein Block, der vor Störungen durch andere Threads geschützt ist, die dieselbe Ressource gemeinsam nutzen und durch das Schlüsselwort „synchronized“ angezeigt werden.

Verwenden der synchronisierten Methode

Jede Methode, die als synchronisiert deklariert ist, wird als synchronisierte Methode bezeichnet. Sie wird auch verwendet, um ein Objekt für eine gemeinsam genutzte Ressource zu sperren. Wenn also ein Thread eine synchronisierte Methode aufruft, übernimmt er automatisch die Sperre für dieses Objekt und gibt sie frei, wenn er seine Aufgabe erledigt hat.

Hinweis: Das Schlüsselwort „synchro“ kann nicht mit Klassen und Variablen verwendet werden. Mit dem Schlüsselwort können nur Methoden und Blöcke verwendet werden.

Warum verwenden Sie die Synchonisierte Methode?

  • Es wird zum Sperren eines Objekts für alle gemeinsam genutzten Ressourcen verwendet.
  • Das Objekt erhält die Sperre, wenn die synchronisierte Methode aufgerufen wird.
  • Die Sperre wird erst freigegeben, wenn der Thread seine Funktion abgeschlossen hat

Syntax:

Acess_modifiers synchronized return_type method_name (Method_Parameters) {
}
class MathService {
    synchronized void getSumOfArray(int[] numbers) {
     int sum = 0;

         for (int number : numbers) {
             System.out.println(Thread.currentThread()
                     .getName()
                     + " adds "
                     + sum + " to "
                     + number + " to get -> "
                     + (sum += number));

             try {
                 Thread.sleep(500);
             } catch (InterruptedException e) {
                 throw new RuntimeException(e);
             }
         }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
    }
}

Erläuterung des Codes:

Führen Sie dieses Beispiel aus und beobachten Sie, dass Thread „0“ zuerst die Sperre des „mathService“-Objekts erhält und diese Sperre ausschließlich verwendet, bis die Ausführung abgeschlossen ist. Thread „0“ und „1“ sind in diesem Code nicht verschachtelt. Die Ausgabe ist wie unten dargestellt.

Ausgang:

Thread-0 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63

Verwenden eines synchronisierten Blocks

Nehmen wir an, Sie möchten nicht die gesamte Methode synchronisieren. Stattdessen möchten Sie einige Codezeilen synchronisieren. Zu diesem Zeitpunkt Syncchronized Block half dabei, die ausgewählte Java Code. SyncAuf synchronisierte Methodensperren wird über die Methode zugegriffen, während auf synchronisierte Blocksperren über das Objekt zugegriffen wird.

class MathService {
    void getSumOfArray(int[] numbers) {
        synchronized (this){
            int sum = 0;

            for (int number : numbers) {
                System.out.println(Thread.currentThread()
                        .getName()
                        + " adds "
                        + sum + " to "
                        + number + " to get -> "
                        + (sum += number));

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
    }
}

Code-Erklärung:

Wenn Sie diesen Code ausführen, werden Sie feststellen, dass er ohne Störungen funktioniert. In der synchronisierten Methode wird die Sperre von der Methode angewendet, im synchronisierten Block jedoch vom Objekt. Stellen Sie sicher, dass die Ausgabe wie unten gezeigt ist.

Ausgang:

Thread-0 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63

Erklärung des Codes:

Wenn Sie diesen Code ausführen, werden Sie feststellen, dass er störungsfrei funktioniert, was wir erwartet haben. In der synchronisierten Methode wird die Sperre von der Methode angewendet, in der synchronisierten Blockmethode jedoch vom Objekt.

Verwenden der statischen Synchronisierung

In Java Synchronisierung: Wenn mehr als ein Objekt vorhanden ist, können zwei Threads die Sperren erwerben und einen synchronisierten Block oder Block mit einer separaten Sperre für jedes Objekt eingeben. Um dies zu vermeiden, kann eine statische Synchronisierung verwendet werden. Synchronisierte Schlüsselwörter werden vor statischen Methoden verwendet.

Hinweis: Bei der statischen Synchronisierung erfolgt der Sperrzugriff auf die Klasse, nicht auf das Objekt und die Methode.

Code zur Veranschaulichung des Problems der Sperrung mehrerer Objekte

class MathService {
    synchronized void getSumOfArray(int[] numbers) {
            int sum = 0;

            for (int number : numbers) {
                System.out.println(Thread.currentThread()
                        .getName()
                        + " adds "
                        + sum + " to "
                        + number + " to get -> "
                        + (sum += number));

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();
        MathService mathService1 = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));
        Thread threadThree = new Thread(() ->
                mathService1.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadFour = new Thread(() ->
                mathService1.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
        threadThree.start();
        threadFour.start();
    }
}

Erklärung des Codes:

Wenn wir eine weitere Instanz des „MathService“ erstellen, führen wir zu Störungen in den Threads, da diese mit den beiden Objekten verschachtelt werden. Beachten Sie, dass Thread „0“ und Thread „2“ mit den beiden Objekten verschachtelt sind, während Thread „1“ und „3“ mit den beiden Objekten verschachtelt sind.

Ausgang:

Thread-0 adds 0 to 10 to get -> 10
Thread-2 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-2 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-2 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-3 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-3 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63
Thread-3 adds 41 to 22 to get -> 63

Gleicher Code mit synchronisierter statischer Methode

class MathService {
    synchronized static void getSumOfArray(int[] numbers) {
            int sum = 0;

            for (int number : numbers) {
                System.out.println(Thread.currentThread()
                        .getName()
                        + " adds "
                        + sum + " to "
                        + number + " to get -> "
                        + (sum += number));

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
    }
}
public class Synchronization {
    public static void main(String[] args) {
        MathService mathService = new MathService();
        MathService mathService1 = new MathService();

        Thread threadOne = new Thread(() ->
                mathService.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadTwo = new Thread(() ->
                mathService.getSumOfArray(new int[]{20, 21, 22}));
        Thread threadThree = new Thread(() ->
                mathService1.getSumOfArray(new int[]{10, 11, 12}));
        Thread threadFour = new Thread(() ->
                mathService1.getSumOfArray(new int[]{20, 21, 22}));

        threadOne.start();
        threadTwo.start();
        threadThree.start();
        threadFour.start();
    }
}

Führen Sie den obigen Code aus und beachten Sie, dass wir nun Thread-Interferenzen beseitigt haben. Die Ausgabe des Codes ist unten dargestellt.

Ausgang:

Thread-0 adds 0 to 10 to get -> 10
Thread-0 adds 10 to 11 to get -> 21
Thread-0 adds 21 to 12 to get -> 33
Thread-3 adds 0 to 20 to get -> 20
Thread-3 adds 20 to 21 to get -> 41
Thread-3 adds 41 to 22 to get -> 63
Thread-2 adds 0 to 10 to get -> 10
Thread-2 adds 10 to 11 to get -> 21
Thread-2 adds 21 to 12 to get -> 33
Thread-1 adds 0 to 20 to get -> 20
Thread-1 adds 20 to 21 to get -> 41
Thread-1 adds 41 to 22 to get -> 63

Vorteile der Synchronisierung

Hier sind die Vorteile bei der Arbeit mit gleichzeitigen Anwendungen:

  • Das Hauptziel der Synchronisation in Java besteht darin, inkonsistente Daten durch die Vermeidung von Thread-Interferenzen zu verhindern.
  • Das synchronisierte Schlüsselwort in Java Bietet Sperren, die einen gegenseitig exklusiven Zugriff auf die gemeinsam genutzte Ressource gewährleisten und Datenkonflikte verhindern.
  • Es verhindert auch die Neuordnung von Codeanweisungen durch Compiler, was zu einem subtilen Parallelitätsproblem führen kann, wenn wir keine volatilen oder synchronisierten Schlüsselwörter verwenden.
  • SyncDas Schlüsselwort hronized liest Daten aus dem Hauptspeicher, dann aus dem Cache und gibt die Sperre frei.
  • Darüber hinaus werden Schreibvorgänge aus dem Hauptspeicher gelöscht, wodurch Speicherinkonsistenzfehler vermieden werden.

Nachteile von SyncChronologie-Mechanismus

SyncHronisierungsmechanismen weisen eine schlechte Leistung auf.

Zum Beispiel

  • Angenommen, es gibt fünf Prozesse: A1, A2, A3, A4 und A5.
  • Sie warten darauf, dass die gemeinsam genutzten Ressourcen jeweils auf einen Thread zugreifen.
  • Alle Prozesse bleiben warten, daher muss der letzte in der Warteschlange warten, bis alle anderen Prozesse abgeschlossen sind.

Zusammenfassung

  • SyncHronisierung bezieht sich auf die Fähigkeit, den Zugriff mehrerer Threads auf jede gemeinsam genutzte Ressource zu steuern.
  • Java verfügt über zwei Arten von Synchronisierungsmethoden: 1) Prozesssynchronisation und 2) Thread-Synchronisierung.
  • Einschließen Java ist um eine interne Einheit herum aufgebaut, die als Monitor oder Sperre bezeichnet wird.
  • Ein Multithread-Programm ist eine Methode oder ein Block, der vor Störungen durch andere Threads geschützt ist, die dieselbe Ressource gemeinsam nutzen, was durch das Schlüsselwort „synchronized“ angezeigt wird.
  • Jede Methode, die als synchronisiert deklariert ist, wird als synchronisierte Methode bezeichnet.
  • In Javawird bei synchronisierten Methodensperren auf die Methode zugegriffen, während bei synchronisierten Blocksperren auf das Objekt zugegriffen wird.
  • Bei der statischen Synchronisierung erfolgt der Sperrzugriff auf die Klasse, nicht auf das Objekt und die Methode.
  • Das Hauptziel der Synchronisation in Java besteht darin, inkonsistente Daten durch die Vermeidung von Thread-Interferenzen zu verhindern.
  • Der größte Nachteil dieser Methode besteht darin, dass alle Prozesse warten, sodass der Letzte in der Warteschlange warten muss, bis alle anderen Prozesse abgeschlossen sind.