CodeGym /Kurse /All lectures for DE purposes /Java-Parallelitätsbibliothek

Java-Parallelitätsbibliothek

All lectures for DE purposes
Level 1, Lektion 506
Verfügbar

Multithreading in Java

Die Java Virtual Machine unterstützt paralleles Rechnen . Alle Berechnungen können im Kontext eines oder mehrerer Threads durchgeführt werden. Wir können problemlos den Zugriff auf dieselbe Ressource oder dasselbe Objekt für mehrere Threads einrichten und einen Thread so einrichten, dass er einen einzelnen Codeblock ausführt.

Jeder Entwickler muss die Arbeit mit Threads während Lese- und Schreibvorgängen für Ressourcen synchronisieren, denen mehrere Threads zugewiesen sind.

Es ist wichtig, dass Sie zum Zeitpunkt des Zugriffs auf die Ressource über aktuelle Daten verfügen, damit ein anderer Thread diese ändern kann und Sie die aktuellsten Informationen erhalten. Selbst wenn wir das Beispiel eines Bankkontos nehmen, können Sie es nicht verwenden, bis das Geld dort eingegangen ist. Daher ist es wichtig, immer über aktuelle Daten zu verfügen. Java verfügt über spezielle Klassen zum Synchronisieren und Verwalten von Threads.

Thread-Objekte

Alles beginnt mit dem Hauptthread (Hauptthread), das heißt, Ihr Programm verfügt zumindest bereits über einen laufenden Thread. Der Hauptthread kann andere Threads mit Callable oder Runnable erstellen . Die Erstellung unterscheidet sich nur im Rückgabeergebnis. Runnable gibt kein Ergebnis zurück und kann keine geprüfte Ausnahme auslösen. Daher erhalten Sie eine gute Gelegenheit, eine effiziente Arbeit mit Dateien aufzubauen, aber dies ist sehr gefährlich und Sie müssen vorsichtig sein.

Es ist auch möglich, die Thread-Ausführung auf einem separaten CPU-Kern zu planen. Das System kann problemlos zwischen Threads wechseln und einen bestimmten Thread mit den richtigen Einstellungen ausführen: Das heißt, der Thread, der die Daten liest, wird zuerst ausgeführt. Sobald wir Daten haben, übergeben wir sie dann an den Thread, der für die Validierung verantwortlich ist. Danach übergeben wir es an den Thread, um einige Geschäftslogiken auszuführen, und ein neuer Thread schreibt sie zurück. In einer solchen Situation verarbeiten 4 Threads nacheinander Daten und alles funktioniert schneller als ein Thread. Jeder dieser Streams wird in einen nativen Betriebssystem-Stream konvertiert, aber wie er konvertiert wird, hängt von der JVM-Implementierung ab.

Die Thread- Klasse wird zum Erstellen und Arbeiten mit Threads verwendet. Es verfügt über Standardkontrollmechanismen sowie abstrakte Mechanismen wie Klassen und Sammlungen von java.util.concurrent .

Thread-Synchronisierung in Java

Die Kommunikation erfolgt durch die gemeinsame Nutzung des Zugriffs auf Objekte. Das ist zwar sehr effektiv, aber gleichzeitig kann man bei der Arbeit sehr leicht einen Fehler machen. Fehler treten in zwei Fällen auf: Thread-Interferenz – wenn ein anderer Thread Ihren Thread stört, und Speicherkonsistenzfehler – Speicherkonsistenz. Um diese Fehler zu beheben und zu verhindern, verfügen wir über verschiedene Synchronisierungsmethoden.

Die Thread-Synchronisierung in Java wird von Monitoren übernommen. Hierbei handelt es sich um einen Mechanismus auf hoher Ebene, der es jeweils nur einem Thread ermöglicht, einen Codeblock auszuführen, der durch denselben Monitor geschützt ist. Das Verhalten von Monitoren wird im Hinblick auf Sperren betrachtet; ein Monitor – ein Schloss.

Bei der Synchronisierung gibt es mehrere wichtige Punkte, auf die Sie achten müssen. Der erste Punkt ist der gegenseitige Ausschluss – nur ein Thread kann den Monitor besitzen, daher bedeutet die Synchronisierung auf dem Monitor, dass, sobald ein Thread einen durch den Monitor geschützten synchronisierten Block betritt, kein anderer Thread den durch den Monitor geschützten Block betreten kann. Dieser Monitor bis zum Der erste Thread verlässt den synchronisierten Block. Das heißt, mehrere Threads können nicht gleichzeitig auf denselben synchronisierten Block zugreifen.

Aber Synchronisierung bedeutet nicht nur gegenseitigen Ausschluss. Durch die Synchronisierung wird sichergestellt, dass Daten, die vor oder innerhalb eines synchronisierten Blocks in den Speicher geschrieben werden, für andere Threads sichtbar werden, die auf demselben Monitor synchronisiert werden. Nachdem wir den Block verlassen haben, geben wir den Monitor frei und ein anderer Thread kann ihn ergreifen und mit der Ausführung dieses Codeblocks beginnen.

Wenn ein neuer Thread den Monitor erfasst, erhalten wir Zugriff auf diesen Codeblock und können ihn ausführen. Zu diesem Zeitpunkt werden die Variablen aus dem Hauptspeicher geladen. Dann können wir alle Einträge sehen, die durch die vorherige Version des Monitors sichtbar gemacht wurden.

Ein einzelner Lese- oder Schreibzugriff auf ein Feld ist atomar, wenn das Feld als volatile deklariert ist (das ist für long und double wichtig) oder wenn alle Zugriffe darauf durch dieselbe Sperre geschützt sind. Ohne Synchronisierung sind Effekte der Neuordnung (Reordering) möglich: In einem falsch synchronisierten Programm kann ein Thread die Änderungen, die ein anderer Thread vorgenommen hat, in einer unerwarteten Reihenfolge sehen.

Der Effekt des gegenseitigen Ausschlusses und der Synchronisierung von Threads, dh ihr korrekter Betrieb, wird nur durch Eingabe eines synchronisierten Blocks oder einer synchronisierten Methode erreicht, die implizit eine Sperre erhält, oder durch explizite Erlangung einer Sperre. Wir werden weiter unten darüber sprechen. Beide Arbeitsweisen wirken sich auf Ihr Gedächtnis aus und es ist wichtig, die Arbeit mit flüchtigen Variablen nicht zu vergessen.

Flüchtige Felder in Java

Das Schlüsselwort volatile löst das Problem der Sichtbarkeit. Wenn ein Thread einen Wert in ein volatile-Feld geschrieben hat, sieht jeder andere Thread, der dieses Feld danach liest, den neuen Wert und keine veraltete Kopie.

In seiner Wirkung auf den Speicher ähnelt das Schreiben in ein volatile-Feld dem Freigeben eines Monitors und das Lesen dem Erwerben des Monitors. Alles, was Thread A vor dem Schreiben in das volatile-Feld geschrieben hat, sieht Thread B garantiert, wenn er aus diesem Feld den geschriebenen Wert gelesen hat. Diese Beziehung heißt happens-before („geschieht vorher“).

Ein einzelner Lese- oder Schreibzugriff auf ein volatile-Feld ist atomar, auch für long und double. Zusammengesetzte Operationen wie count++ (lesen, erhöhen, schreiben) sind es dagegen nicht: Zwischen den Schritten kann ein anderer Thread zum Zug kommen, und ein Teil der Erhöhungen geht verloren. Gegenseitigen Ausschluss bietet volatile nicht. Damit eine zusammengesetzte Operation atomar ausgeführt wird, braucht man synchronized, Lock oder Klassen wie AtomicInteger, AtomicLong usw.

Java gleichzeitig

Wenn Sie eine hocheffiziente Multithread-Anwendung erstellen möchten, müssen Sie die Klassen aus der JavaConcurrent- Bibliothek verwenden , die sich im Paket java.util.concurrent befinden .

Die Bibliothek ist sehr umfangreich und verfügt über unterschiedliche Funktionen. Werfen wir also einen Blick auf den Inhalt und teilen ihn in einige Module auf:

Java gleichzeitig

Concurrent Collections ist eine Reihe von Sammlungen für die Arbeit in einer Multithread-Umgebung. Anstelle des Basis-Wrappers Collections.synchronizedList mit blockierendem Zugriff auf die gesamte Sammlung werden Sperren für Datensegmente verwendet oder wartefreie Algorithmen zum parallelen Lesen von Daten.

Warteschlangen – nicht blockierende und blockierende Warteschlangen für die Arbeit in einer Multithread-Umgebung. Nicht blockierende Warteschlangen konzentrieren sich auf Geschwindigkeit und Betrieb, ohne Threads zu blockieren. Blockierungswarteschlangen eignen sich für die Arbeit, wenn Sie die Producer- oder Consumer -Threads „verlangsamen“ müssen. Wenn beispielsweise einige Bedingungen nicht erfüllt sind, ist die Warteschlange leer oder voll oder es gibt keinen freien Verbraucher .

Synchronizer sind Dienstprogramme zum Synchronisieren von Threads. Sie sind eine mächtige Waffe im „Parallel“-Computing.

Executors ist ein Framework für die bequemere und einfachere Erstellung von Thread-Pools. Es ist einfach, die Planung asynchroner Aufgaben einzurichten und Ergebnisse zu erhalten.

Sperren sind viele flexible Thread-Synchronisationsmechanismen im Vergleich zu den grundlegenden Mechanismen „ synced “, „ wait “, „notify “ und „notifyAll“ .

Atomics sind Klassen, die atomare Operationen an Grundelementen und Referenzen unterstützen können.

Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION