Jede Anwendung kann mehrere Prozesse (Instanzen) haben. Jeder dieser Prozesse kann entweder als einzelner Thread oder als mehrere Threads zugewiesen werden. In diesem Tutorial erfahren Sie, wie Sie mehrere Aufgaben gleichzeitig ausführen und mehr über Threads und die Synchronisierung zwischen Threads erfahren.
In diesem Tutorial lernen wir:
- Was ist Single Thread
- Was ist Multithreading in Java?
- Thread-Lebenszyklus in Java
- Java-Thread-Synchronisation
- Java Multithreading Beispiel
Was ist Single Thread?
Ein einzelner Thread ist im Grunde eine leichte und kleinste Verarbeitungseinheit. Java verwendet Threads mithilfe einer "Thread-Klasse".
Es gibt zwei Arten von Threads: Benutzer-Threads und Daemon-Threads (Daemon-Threads werden verwendet, wenn die Anwendung bereinigt werden soll, und im Hintergrund).
Wenn eine Anwendung zum ersten Mal gestartet wird, wird ein Benutzerthread erstellt. Danach können wir viele Benutzer- und Daemon-Threads erstellen.
Beispiel für einen einzelnen Thread:
Paket Demotest;öffentliche Klasse GuruThread{public static void main (String [] args) {System.out.println ("Single Thread");}}}}
Vorteile eines einzelnen Threads:
- Reduziert den Overhead in der Anwendung, wenn einzelne Threads im System ausgeführt werden
- Außerdem werden die Wartungskosten der Anwendung reduziert.
Was ist Multithreading in Java?
MULTITHREADING in Java ist ein Prozess, bei dem zwei oder mehr Threads gleichzeitig ausgeführt werden, um die CPU optimal zu nutzen . Multithread-Anwendungen führen zwei oder mehr Threads aus, die gleichzeitig ausgeführt werden. Daher wird es in Java auch als Parallelität bezeichnet. Jeder Thread läuft parallel zueinander. Mehrere Threads weisen keinen separaten Speicherbereich zu, daher sparen sie Speicher. Außerdem dauert das Umschalten des Kontexts zwischen Threads weniger lange.
Beispiel für Multi-Thread:
Paket Demotest;öffentliche Klasse GuruThread1 implementiert Runnable{public static void main (String [] args) {Thread guruThread1 = neuer Thread ("Guru1");Thread guruThread2 = neuer Thread ("Guru2");guruThread1.start ();guruThread2.start ();System.out.println ("Thread-Namen folgen:");System.out.println (guruThread1.getName ());System.out.println (guruThread2.getName ());}}@Overridepublic void run () {}}}}
Vorteile von Multithread:
- Die Benutzer werden nicht blockiert, da Threads unabhängig sind und wir mehrere Vorgänge gleichzeitig ausführen können
- Da die Threads unabhängig sind, werden die anderen Threads nicht beeinflusst, wenn ein Thread eine Ausnahme erfüllt.
Thread-Lebenszyklus in Java
Der Lebenszyklus eines Threads:
Es gibt verschiedene Phasen des Lebenszyklus des Gewindes, wie in der obigen Abbildung gezeigt:
- Neu
- Runnable
- Laufen
- Warten
- tot
- Neu: In dieser Phase wird der Thread mit der Klasse "Thread-Klasse" erstellt. Er bleibt in diesem Zustand, bis das Programm den Thread startet . Es ist auch als geborener Faden bekannt.
- Ausführbar: Auf dieser Seite wird die Instanz des Threads mit einer Startmethode aufgerufen. Die Thread-Steuerung wird dem Scheduler übergeben, um die Ausführung zu beenden. Es hängt vom Scheduler ab, ob der Thread ausgeführt werden soll.
- Wird ausgeführt : Wenn der Thread ausgeführt wird, wird der Status in den Status "Ausführen" geändert. Der Scheduler wählt einen Thread aus dem Thread-Pool aus und beginnt mit der Ausführung in der Anwendung.
- Warten: Dies ist der Status, in dem ein Thread warten muss. Da in der Anwendung mehrere Threads ausgeführt werden, ist eine Synchronisierung zwischen den Threads erforderlich. Daher muss ein Thread warten, bis der andere Thread ausgeführt wird. Daher wird dieser Zustand als Wartezustand bezeichnet.
- Tot: Dies ist der Zustand, in dem der Thread beendet wird. Der Thread befindet sich im laufenden Zustand und befindet sich nach Abschluss der Verarbeitung im "toten Zustand".
Einige der am häufigsten verwendeten Methoden für Threads sind:
Methode | Beschreibung |
---|---|
Start() | Diese Methode startet die Ausführung des Threads und JVM ruft die run () -Methode für den Thread auf. |
Schlaf (in Millisekunden) | Diese Methode lässt den Thread in den Ruhezustand versetzt werden, daher wird die Ausführung des Threads für die angegebenen Millisekunden angehalten, und danach beginnt der Thread erneut mit der Ausführung. Dies hilft bei der Synchronisation der Threads. |
getName () | Es gibt den Namen des Threads zurück. |
setPriority (int newpriority) | Es ändert die Priorität des Threads. |
Ausbeute () | Es bewirkt, dass der aktuelle Thread angehalten wird und andere Threads ausgeführt werden. |
Beispiel: In diesem Beispiel erstellen wir einen Thread und untersuchen die für Threads verfügbaren integrierten Methoden.
Paket Demotest;Die öffentliche Klasse thread_example1 implementiert Runnable {@Overridepublic void run () {}}public static void main (String [] args) {Thread guruthread1 = neuer Thread ();guruthread1.start ();Versuchen {guruthread1.sleep (1000);} catch (InterruptedException e) {// TODO Automatisch generierter Fangblocke.printStackTrace ();}}guruthread1.setPriority (1);int gurupriority = guruthread1.getPriority ();System.out.println (Gurupriorität);System.out.println ("Thread läuft");}}}}
Erläuterung des Codes:
- Codezeile 2: Wir erstellen eine Klasse "thread_Example1", die die Runnable-Schnittstelle implementiert (sie sollte von jeder Klasse implementiert werden, deren Instanzen vom Thread ausgeführt werden sollen.)
- Codezeile 4: Sie überschreibt die Ausführungsmethode der ausführbaren Schnittstelle, da diese Methode unbedingt überschrieben werden muss
- Codezeile 6: Hier haben wir die Hauptmethode definiert, mit der wir die Ausführung des Threads starten.
- Codezeile 7: Hier erstellen wir einen neuen Thread-Namen als "guruthread1", indem wir eine neue Thread-Klasse instanziieren.
- Codezeile 8: Wir verwenden die "start" -Methode des Threads unter Verwendung der "guruthread1" -Instanz. Hier wird der Thread ausgeführt.
- Codezeile 10: Hier verwenden wir die "sleep" -Methode des Threads unter Verwendung der "guruthread1" -Instanz. Daher wird der Thread 1000 Millisekunden lang schlafen.
- Code 9-14: Hier haben wir die Schlafmethode in den try catch-Block eingefügt, da eine aktivierte Ausnahme vorliegt, dh eine unterbrochene Ausnahme.
- Codezeile 15: Hier setzen wir die Priorität des Threads von der Priorität auf 1
- Codezeile 16: Hier erhalten wir die Priorität des Threads mit getPriority ()
- Codezeile 17: Hier drucken wir den von getPriority abgerufenen Wert
- Codezeile 18: Hier schreiben wir einen Text, den der Thread ausführt.
Wenn Sie den obigen Code ausführen, erhalten Sie die folgende Ausgabe:
Ausgabe:
5 ist die Thread-Priorität und Thread Running ist der Text, der die Ausgabe unseres Codes ist.
Java-Thread-Synchronisation
Beim Multithreading gibt es das asynchrone Verhalten der Programme. Wenn ein Thread Daten schreibt und ein anderer Thread gleichzeitig Daten liest, kann dies zu Inkonsistenzen in der Anwendung führen.
Wenn zwei oder mehr Threads auf die gemeinsam genutzten Ressourcen zugreifen müssen, wird der Synchronisationsansatz verwendet.
Java hat synchronisierte Methoden bereitgestellt, um synchronisiertes Verhalten zu implementieren.
Bei diesem Ansatz kann kein anderer Thread diese Methode für dasselbe Objekt aufrufen, sobald der Thread in den synchronisierten Block gelangt. Alle Threads müssen warten, bis dieser Thread den synchronisierten Block beendet und daraus hervorgeht.
Auf diese Weise hilft die Synchronisation in einer Multithread-Anwendung. Ein Thread muss warten, bis der andere Thread seine Ausführung beendet hat. Erst dann können die anderen Threads ausgeführt werden.
Es kann in folgender Form geschrieben werden:
Synchronisiert (Objekt){// Block der zu synchronisierenden Anweisungen}}
Java Multithreading Beispiel
In diesem Beispiel nehmen wir zwei Threads und rufen die Namen des Threads ab.
Beispiel 1:
GuruThread1.javaPaket Demotest;öffentliche Klasse GuruThread1 implementiert Runnable {/ *** @param args* /public static void main (String [] args) {Thread guruThread1 = neuer Thread ("Guru1");Thread guruThread2 = neuer Thread ("Guru2");guruThread1.start ();guruThread2.start ();System.out.println ("Thread-Namen folgen:");System.out.println (guruThread1.getName ());System.out.println (guruThread2.getName ());}}@Overridepublic void run () {}}}}
Erläuterung des Codes:
- Codezeile 3: Wir haben eine Klasse "GuruThread1" verwendet, die Runnable implementiert (sie sollte von jeder Klasse implementiert werden, deren Instanzen vom Thread ausgeführt werden sollen.)
- Codezeile 8: Dies ist die Hauptmethode der Klasse
- Codezeile 9: Hier instanziieren wir die Thread-Klasse und erstellen eine Instanz mit dem Namen "guruThread1" und erstellen einen Thread.
- Codezeile 10: Hier instanziieren wir die Thread-Klasse und erstellen eine Instanz mit dem Namen "guruThread2" und erstellen einen Thread.
- Codezeile 11: Wir starten den Thread dh guruThread1.
- Codezeile 12: Wir starten den Thread dh guruThread2.
- Codezeile 13: Ausgabe des Textes als "Thread-Namen folgen:"
- Codezeile 14: Abrufen des Namens von Thread 1 mithilfe der Methode getName () der Thread-Klasse.
- Codezeile 15: Abrufen des Namens von Thread 2 mithilfe der Methode getName () der Thread-Klasse.
Wenn Sie den obigen Code ausführen, erhalten Sie die folgende Ausgabe:
Ausgabe:
Thread-Namen werden hier als ausgegeben
- Guru1
- Guru2
Beispiel 2:
In diesem Beispiel lernen wir die überschreibenden Methoden run () und start () einer ausführbaren Schnittstelle kennen, erstellen zwei Threads dieser Klasse und führen sie entsprechend aus.
Außerdem nehmen wir zwei Klassen,
- Eine, die die ausführbare Schnittstelle implementiert und
- Eine andere, die die Hauptmethode hat und entsprechend ausführt.
Paket Demotest;öffentliche Klasse GuruThread2 {public static void main (String [] args) {// TODO Automatisch generierter MethodenstubGuruThread3 threadguru1 = neuer GuruThread3 ("guru1");threadguru1.start ();GuruThread3 threadguru2 = neuer GuruThread3 ("guru2");threadguru2.start ();}}}}Klasse GuruThread3 implementiert Runnable {Gewindegurutfaden;privater String-Guruname;GuruThread3 (String name) {Guruname = Name;}}@Overridepublic void run () {System.out.println ("Thread läuft" + Guruname);für (int i = 0; i <4; i ++) {System.out.println (i);System.out.println (Guruname);Versuchen {Thread.sleep (1000);} catch (InterruptedException e) {System.out.println ("Thread wurde unterbrochen");}}}}}}public void start () {System.out.println ("Thread gestartet");if (guruthread == null) {guruthread = neuer Thread (dies, Guruname);guruthread.start ();}}}}}}
Erläuterung des Codes:
- Codezeile 2: Hier nehmen wir eine Klasse "GuruThread2", die die Hauptmethode enthält.
- Codezeile 4: Hier nehmen wir eine Hauptmethode der Klasse.
- Codezeile 6-7: Hier erstellen wir eine Instanz der Klasse GuruThread3 (die in den folgenden Zeilen des Codes erstellt wird) als "threadguru1" und starten den Thread.
- Codezeile 8-9: Hier erstellen wir eine weitere Instanz der Klasse GuruThread3 (die in den folgenden Zeilen des Codes erstellt wird) als "threadguru2" und starten den Thread.
- Codezeile 11: Hier erstellen wir eine Klasse "GuruThread3", die die ausführbare Schnittstelle implementiert (sie sollte von jeder Klasse implementiert werden, deren Instanzen vom Thread ausgeführt werden sollen.)
- Codezeile 13-14: Wir nehmen zwei Klassenvariablen, von denen eine vom Typ Threadklasse und die andere von der Zeichenfolgenklasse ist.
- Codezeile 15-18: Wir überschreiben den GuruThread3-Konstruktor, der ein Argument als Zeichenfolgentyp (der Thread-Name) verwendet, der der Klassenvariablen Guruname zugewiesen wird, und daher wird der Name des Threads gespeichert.
- Codezeile 20: Hier überschreiben wir die run () -Methode der ausführbaren Schnittstelle.
- Codezeile 21: Wir geben den Threadnamen mit der Anweisung println aus.
- Codezeile 22-31: Hier verwenden wir eine for-Schleife mit einem auf 0 initialisierten Zähler, und sie sollte nicht kleiner als 4 sein (wir können eine beliebige Zahl annehmen, daher wird die Schleife hier viermal ausgeführt) und den Zähler inkrementieren. Wir drucken den Thread-Namen und lassen den Thread innerhalb eines Try-Catch-Blocks 1000 Millisekunden lang in den Ruhezustand versetzt werden, da die Sleep-Methode die aktivierte Ausnahme ausgelöst hat.
- Codezeile 33: Hier überschreiben wir die Startmethode der ausführbaren Schnittstelle.
- Codezeile 35: Wir geben den Text "Thread gestartet" aus.
- Codezeile 36-40: Hier nehmen wir eine if-Bedingung, um zu überprüfen, ob der Klassenvariable guruthread einen Wert enthält oder nicht. Wenn es null ist, erstellen wir eine Instanz mit der Thread-Klasse, die den Namen als Parameter verwendet (Wert, der im Konstruktor zugewiesen wurde). Danach wird der Thread mit der Methode start () gestartet.
Wenn Sie den obigen Code ausführen, erhalten Sie die folgende Ausgabe:
Ausgabe :
Es gibt zwei Threads, daher erhalten wir zweimal die Meldung "Thread gestartet".
Wir erhalten die Namen des Threads, wie wir sie ausgegeben haben.
Es geht in die for-Schleife, in der der Zähler und der Threadname gedruckt werden und der Zähler mit 0 beginnt.
Die Schleife wird dreimal ausgeführt und dazwischen wird der Thread 1000 Millisekunden lang geschlafen.
Daher bekommen wir zuerst Guru1, dann Guru2 und dann wieder Guru2, weil der Thread hier 1000 Millisekunden schläft und dann als nächstes Guru1 und wieder Guru1, Thread 1000 Millisekunden, also bekommen wir Guru2 und dann Guru1.
Zusammenfassung :
In diesem Tutorial haben wir Multithread-Anwendungen in Java und die Verwendung von Einzel- und Multithreads gesehen.
- Beim Multithreading werden Benutzer nicht blockiert, da Threads unabhängig sind und mehrere Vorgänge gleichzeitig ausführen können
- Verschiedene Phasen des Lebenszyklus des Fadens sind:
- Neu
- Runnable
- Laufen
- Warten
- tot
- Wir haben auch etwas über die Synchronisation zwischen Threads gelernt, damit die Anwendung reibungslos ausgeführt werden kann.
- Multithreading erleichtert viel mehr Anwendungsaufgaben.