Multithreading in Java


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 erfahren mehr über Threads und die Synchronisierung zwischen Threads.

Was ist Single-Thread?

Ein einzelner Thread in Java ist im Grunde genommen ein Leichtgewicht und die kleinste Verarbeitungseinheit. Java verwendet Threads mithilfe einer „Thread-Klasse“. Es gibt zwei Arten von Threads – Benutzer-Thread und Daemon-Thread (Daemon-Threads werden verwendet, wenn wir die Anwendung bereinigen möchten und werden im Hintergrund verwendet). Wenn eine Anwendung zum ersten Mal gestartet wird, wird ein Benutzer-Thread erstellt. Danach können wir viele Benutzer-Threads und Daemon-Threads erstellen.

Beispiel für einen einzelnen Thread:

package demotest;

public class GuruThread
{
       public static void main(String[] args) {
              System.out.println("Single Thread");
       }
}

Vorteile von Single-Thread:

  • Reduziert den Overhead in der Anwendung, da ein einzelner Thread im System ausgeführt wird
  • 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 maximal auszulasten. Multithread-Anwendungen führen zwei oder mehr Threads gleichzeitig aus. Daher wird es auch als Parallelität bezeichnet in Java. Jeder Thread läuft parallel zu den anderen. Mehrere Threads belegen keinen separaten Speicherbereich und sparen daher Speicher. Außerdem dauert der Kontextwechsel zwischen Threads weniger Zeit.

Beispiel für Multithread:

package demotest;
public class GuruThread1 implements Runnable
{
       public static void main(String[] args) {
        Thread guruThread1 = new Thread("Guru1");
        Thread guruThread2 = new Thread("Guru2");
        guruThread1.start();
        guruThread2.start();
        System.out.println("Thread names are following:");
        System.out.println(guruThread1.getName());
        System.out.println(guruThread2.getName());
    }
    @Override
    public void run() {
    }
}

Vorteile von Multithread:

  • Die Benutzer werden nicht blockiert, da die Threads unabhängig sind und wir mehrere Vorgänge gleichzeitig ausführen können.
  • Da die Threads unabhängig sind, sind die anderen Threads nicht betroffen, wenn ein Thread auf eine Ausnahme trifft.

Thread-Lebenszyklus in Java

Der Lebenszyklus eines Threads:

Thread-Lebenszyklus in Java
Thread-Lebenszyklus in Java

Es gibt verschiedene Phasen im Lebenszyklus eines Threads, wie im obigen Diagramm dargestellt:

  1. NEU
  2. Lauffähig
  3. Laufen
  4. Warten
  5. Tot
  1. Neu: In dieser Phase wird der Thread mithilfe der Klasse „Thread-Klasse“ erstellt. Er bleibt in diesem Zustand, bis das Programm ausgeführt wird beginnt der Faden. Es ist auch als Born Thread bekannt.
  2. Lauffähig: Auf dieser Seite wird die Instanz des Threads mit einer Startmethode aufgerufen. Die Thread-Steuerung wird dem Scheduler übergeben, um die Ausführung abzuschließen. Es hängt vom Scheduler ab, ob der Thread ausgeführt werden soll.
  3. Laufen: Wenn die Ausführung des Threads beginnt, ändert sich der Status in den Status „Wird ausgeführt“. Der Scheduler wählt einen Thread aus dem Thread-Pool aus und beginnt mit der Ausführung in der Anwendung.
  4. Warten: Dies ist der Zustand, 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.
  5. Tot: Dies ist der Zustand, wenn der Thread beendet wird. Der Thread befindet sich im laufenden Zustand und befindet sich, sobald er die Verarbeitung abgeschlossen hat, im „toten Zustand“.


Methoden des Multithreading in Java

Einige der häufig verwendeten Methoden für Threads sind:

Method Beschreibung
Start() Diese Methode startet die Ausführung des Threads und JVM ruft die run()-Methode für den Thread auf.
Schlaf (int Millisekunden) Diese Methode versetzt den Thread in den Ruhezustand, sodass die Ausführung des Threads für die angegebenen Millisekunden angehalten wird und danach erneut mit der Ausführung des Threads begonnen wird. Dies hilft bei der Synchronisierung der Threads.
getName () Es gibt den Namen des Threads zurück.
setPriority(int newpriority) Es ändert die Priorität des Threads.
Ertrag () Dadurch wird der aktuelle Thread angehalten und andere Threads ausgeführt.

Ejemplo: In diesem Multithreading-Programm in Java Beispiel: Wir werden einen Thread erstellen und die für Threads verfügbaren integrierten Methoden untersuchen.

package demotest;
public class thread_example1 implements Runnable {
    @Override
    public void run() {
    }
    public static void main(String[] args) {
        Thread guruthread1 = new Thread();
        guruthread1.start();
        try {
            guruthread1.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        guruthread1.setPriority(1);
        int gurupriority = guruthread1.getPriority();
        System.out.println(gurupriority);
        System.out.println("Thread Running");
  }
}

Erklärung 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: Es ü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 werden die „Start“-Methode des Threads mit der Instanz „guruthread1“ verwenden. Hier beginnt die Ausführung des Threads.
  • Codezeile 10: Hier verwenden wir die „sleep“-Methode des Threads mit der Instanz „guruthread1“. Daher schläft der Thread 1000 Millisekunden lang.
  • Code 9-14: Hier haben wir die Sleep-Methode in den Try-Catch-Block eingefügt, da dort eine überprüfte Ausnahme auftritt, dh eine unterbrochene Ausnahme.
  • Codezeile 15: Hier setzen wir die Priorität des Threads auf 1, unabhängig von der Priorität, die er hatte
  • 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, in dem der Thread läuft.

Wenn Sie den obigen Code ausführen, erhalten Sie die folgende Ausgabe:

Thread-Beispiel in Java

Ausgang:

5 ist die Thread-Priorität und Thread Running ist der Text, der die Ausgabe unseres Codes darstellt.

Java Thread SyncHronisierung

Beim Multithreading kommt es zu einem asynchronen 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 ein Synchronisierungsansatz verwendet. Java hat synchronisierte Methoden zur Implementierung synchronisierten Verhaltens bereitgestellt.

Bei diesem Ansatz kann kein anderer Thread diese Methode für dasselbe Objekt aufrufen, sobald der Thread den synchronisierten Block erreicht hat. Alle Threads müssen warten, bis dieser Thread den synchronisierten Block beendet und ihn verlässt. Auf diese Weise hilft die Synchronisierung bei einer Multithread-Anwendung. Ein Thread muss warten, bis der andere Thread seine Ausführung beendet hat, erst dann dürfen die anderen Threads ausgeführt werden.

Es kann in der folgenden Form geschrieben werden:

Synchronized(object)
{  
        //Block of statements to be synchronized
}

Multithreading in Java Beispielprogramme

In diesem Multithreading Java Beispiel: Wir nehmen zwei Threads und holen die Namen der Threads.

Example1:

GuruThread1.java
package demotest;
public class GuruThread1 implements Runnable{

    /**
     * @param args
     */
    public static void main(String[] args) {
        Thread guruThread1 = new Thread("Guru1");
        Thread guruThread2 = new Thread("Guru2");
        guruThread1.start();
        guruThread2.start();
        System.out.println("Thread names are following:");
        System.out.println(guruThread1.getName());
        System.out.println(guruThread2.getName());
    }
    @Override
    public void run() {
    }
}

Erklärung des Codes:

  • Codezeile 3: Wir haben eine Klasse „GuruThread1“ genommen, 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, erstellen eine Instanz mit dem Namen „guruThread1“ und erstellen einen Thread.
  • Codezeile 10: Hier instanziieren wir die Thread-Klasse, 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 „Die Threadnamen lauten wie folgt:“
  • Codezeile 14: Den Namen von Thread 1 mithilfe der Methode getName() der Thread-Klasse ermitteln.
  • Codezeile 15: Den Namen von Thread 2 mithilfe der Methode getName() der Thread-Klasse ermitteln.

Wenn Sie den obigen Code ausführen, erhalten Sie die folgende Ausgabe:

Java Multithreading-Beispiel

Ausgang:

Thread-Namen werden hier ausgegeben als

  • Guru1
  • Guru2

Beispiel 2:

In diesem Multithreading in Java Beispiel: Wir lernen, wie man die Methoden run() und start() einer ausführbaren Schnittstelle überschreibt und zwei Threads dieser Klasse erstellt und sie entsprechend ausführt.

Außerdem nehmen wir an zwei Kursen teil,

  • Eines, das die ausführbare Schnittstelle implementiert und
  • Eine andere, die die Hauptmethode hat und entsprechend ausgeführt wird.
package demotest;
public class GuruThread2 {
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  GuruThread3 threadguru1 = new GuruThread3("guru1");
  threadguru1.start();
  GuruThread3 threadguru2 = new GuruThread3("guru2");
  threadguru2.start();
 }
}
class GuruThread3 implements Runnable {
 Thread guruthread;
 private String guruname;
 GuruThread3(String name) {
  guruname = name;
 }
 @Override
 public void run() {
  System.out.println("Thread running" + guruname);
  for (int i = 0; i < 4; i++) {
   System.out.println(i);
   System.out.println(guruname);
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    System.out.println("Thread has been interrupted");
   }
  }
 }
 public void start() {
  System.out.println("Thread started");
  if (guruthread == null) {
   guruthread = new Thread(this, guruname);
   guruthread.start();
  }
 }
}

Erklärung des Codes:

  • Codezeile 2: Hier nehmen wir eine Klasse „GuruThread2“, die die Hauptmethode enthalten wird.
  • 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 Thread-Klasse und die andere vom Typ String-Klasse ist.
  • Codezeile 15-18: Wir überschreiben den GuruThread3-Konstruktor, der ein Argument als String-Typ (den Thread-Namen) akzeptiert, der der Klassenvariablen guruname zugewiesen wird und somit den Namen des Threads speichert.
  • Codezeile 20: Hier überschreiben wir die run()-Methode der ausführbaren Schnittstelle.
  • Codezeile 21: Wir geben den Thread-Namen mit der println-Anweisung aus.
  • Codezeile 22-31: Hier verwenden wir eine for-Schleife mit einem auf 0 initialisierten Zähler, der nicht kleiner als 4 sein sollte (wir können jede beliebige Zahl annehmen, daher wird die Schleife hier viermal ausgeführt) und erhöhen den Zähler. Wir geben den Thread-Namen aus und sorgen dafür, dass der Thread innerhalb eines Try-Catch-Blocks 4 Millisekunden lang in den Ruhezustand versetzt wird, da die Sleep-Methode eine geprüfte Ausnahme auslöst.
  • Codezeile 33: Hier überschreiben wir die Startmethode der ausführbaren Schnittstelle.
  • Codezeile 35: Wir geben den Text „Thread gestartet“ aus.
  • Codezeile 36-40: Hier verwenden wir eine if-Bedingung, um zu prüfen, ob die Klassenvariable guruthread einen Wert enthält oder nicht. Wenn es null ist, erstellen wir eine Instanz mithilfe der Thread-Klasse, die den Namen als Parameter verwendet (der Wert wurde im Konstruktor zugewiesen). Danach wird der Thread mit der Methode start() gestartet.

Wenn Sie den obigen Code ausführen, erhalten Sie die folgende Ausgabe:

Multithreading-Beispiel in Java

Ausgang:

Da es zwei Threads gibt, erhalten wir zweimal die Meldung „Thread gestartet“.

Wir erhalten die Namen der Threads so, wie wir sie ausgegeben haben.

Es geht in die for-Schleife, in der wir den Zähler und den Thread-Namen drucken und der Zähler mit 0 beginnt.

Die Schleife wird dreimal ausgeführt und dazwischen ruht der Thread für 1000 Millisekunden.

Daher erhalten wir zuerst Guru1, dann Guru2 und dann noch einmal Guru2, weil der Thread hier 1000 Millisekunden lang schläft, und dann folgt Guru1 und wieder Guru1, der Thread schläft 1000 Millisekunden lang, also erhalten wir Guru2 und dann Guru1.

Zusammenfassung

In diesem Tutorial haben wir Multithread-Anwendungen gesehen in Java und wie man Single- und Multi-Thread verwendet in Java.

  • Erklären Sie Multithreading in Java: 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 Threads sind:
    • NEU
    • Lauffähig
    • Laufen
    • Warten
    • Tot
  • Wir haben auch davon erfahren Synchronisation zwischen Threads, die dazu beitragen, dass die Anwendung reibungslos läuft.
  • Multithread-Programmierung in Java erleichtert viele weitere Anwendungsaufgaben.