CodeGym /Java-Blog /Random-DE /Multithreading in Java
Autor
Oleksandr Miadelets
Head of Developers Team at CodeGym

Multithreading in Java

Veröffentlicht in der Gruppe Random-DE
Hallo! Zunächst einmal herzlichen Glückwunsch: Sie haben das Thema Multithreading in Java erreicht! Das ist eine ernsthafte Leistung – Sie haben einen langen Weg zurückgelegt. Aber bereiten Sie sich vor: Dies ist eines der schwierigsten Themen im Kurs. Und es ist nicht so, dass wir hier komplexe Klassen oder viele Methoden verwenden: Tatsächlich werden wir weniger als zwanzig verwenden. Vielmehr müssen Sie Ihre Denkweise ein wenig ändern. Zuvor wurden Ihre Programme sequentiell ausgeführt. Einige Codezeilen kamen nach anderen, einige Methoden folgten nach anderen und im Grunde war alles klar. Zuerst haben wir etwas berechnet, dann das Ergebnis auf der Konsole angezeigt und dann wurde das Programm beendet. Um Multithreading zu verstehen, ist es besser, in Begriffen der Parallelität zu denken. Beginnen wir mit etwas ganz Einfachem: ) Stellen Sie sich vor, Ihre Familie zieht von einem Haus in ein anderes. Das Zusammentragen aller Ihrer Bücher wird ein wichtiger Teil des Umzugs sein. Sie haben viele Bücher angesammelt und müssen sie in Kartons packen. Derzeit sind Sie der Einzige, der verfügbar ist. Mama bereitet Essen vor, Bruder packt Kleidung und Schwester geht in den Laden. Alleine schaffst du es schon irgendwie. Früher oder später werden Sie die Aufgabe selbst erledigen, aber es wird viel Zeit in Anspruch nehmen. Allerdings kommt deine Schwester in 20 Minuten aus dem Laden zurück und hat nichts anderes zu tun. Damit sie sich dir anschließen kann. Die Aufgabe hat sich nicht geändert: Bücher in Kisten packen. Aber es wird doppelt so schnell durchgeführt. Warum? Denn die Arbeit läuft parallel. Zwei verschiedene „Threads“ (Sie und Ihre Schwester) führen gleichzeitig dieselbe Aufgabe aus. Und wenn sich nichts ändert, dann gibt es einen großen Zeitunterschied im Vergleich zu der Situation, in der man alles alleine macht. Wenn Bruder seine Arbeit bald erledigt, kann er Ihnen helfen und alles wird noch schneller gehen.

Durch Multithreading gelöste Probleme

Multithreading wurde eigentlich erfunden, um zwei wichtige Ziele zu erreichen:
  1. Machen Sie mehrere Dinge gleichzeitig.

    Im obigen Beispiel führten verschiedene Threads (Familienmitglieder) mehrere Aktionen parallel aus: Sie spülten Geschirr, gingen in den Laden und packten Sachen.

    Wir können ein Beispiel anbieten, das näher an der Programmierung liegt. Angenommen, Sie haben ein Programm mit einer Benutzeroberfläche. Wenn Sie im Programm auf „Weiter“ klicken, sollten einige Berechnungen durchgeführt werden und der Benutzer sollte den folgenden Bildschirm sehen. Wenn diese Aktionen nacheinander ausgeführt würden, würde das Programm einfach hängen bleiben, nachdem der Benutzer auf die Schaltfläche „Weiter“ geklickt hat. Dem Benutzer wird der Bildschirm mit der Schaltfläche „Weiter“ angezeigt, bis das Programm alle internen Berechnungen durchführt und den Teil erreicht, in dem die Benutzeroberfläche aktualisiert wird.

    Nun, ich schätze, wir werden ein paar Minuten warten!

    Multithreading in Java: Was es ist, seine Vorteile und häufige Fallstricke – 3

    Oder wir könnten unser Programm überarbeiten oder, wie Programmierer sagen, „parallelisieren“. Lassen Sie uns unsere Berechnungen in einem Thread durchführen und die Benutzeroberfläche in einem anderen zeichnen. Die meisten Computer verfügen über genügend Ressourcen, um dies zu tun. Wenn wir diesen Weg wählen, friert das Programm nicht ein und der Benutzer kann reibungslos zwischen den Bildschirmen wechseln, ohne sich Gedanken darüber machen zu müssen, was im Inneren passiert. Das eine stört das andere nicht :)

  2. Führen Sie Berechnungen schneller durch.

    Hier ist alles viel einfacher. Wenn unser Prozessor über mehrere Kerne verfügt, was bei den meisten Prozessoren heutzutage der Fall ist, können mehrere Kerne unsere Aufgabenliste parallel bearbeiten. Wenn wir 1000 Aufgaben ausführen müssen und jede eine Sekunde dauert, kann ein Kern die Liste natürlich in 1000 Sekunden abschließen, zwei Kerne in 500 Sekunden, drei in etwas mehr als 333 Sekunden usw.

Aber wie Sie in dieser Lektion bereits gelesen haben, sind heutige Systeme sehr intelligent und können sogar auf einem Rechenkern Parallelität bzw. Pseudoparallelität erreichen, bei der Aufgaben abwechselnd ausgeführt werden. Lassen Sie uns vom Allgemeinen zum Besonderen übergehen und die wichtigste Klasse in der Java-Multithreading-Bibliothek kennenlernen – java.lang.Thread. Streng genommen werden Java-Threads durch Instanzen der Thread- Klasse dargestellt. Das bedeutet, dass Sie zum Erstellen und Ausführen von 10 Threads 10 Instanzen dieser Klasse benötigen. Schreiben wir das einfachste Beispiel:

public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("I'm Thread! My name is " + getName());
   }
}
Um Threads zu erstellen und auszuführen, müssen wir eine Klasse erstellen und dafür sorgen, dass sie java.lang erbt . Thread- Klasse und überschreiben Sie deren run()- Methode. Diese letzte Anforderung ist sehr wichtig. In der run()- Methode definieren wir die Logik für die Ausführung unseres Threads. Wenn wir nun eine Instanz von MyFirstThread erstellen und ausführen, zeigt die Methode run() eine Zeile mit einem Namen an: Die Methode getName() zeigt den Systemnamen des Threads an, der automatisch zugewiesen wird. Aber warum sprechen wir zögernd? Lassen Sie uns eines erstellen und es herausfinden!

public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {

           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
Konsolenausgabe: Ich bin Thread! Mein Name ist Thread-2, ich bin Thread! Mein Name ist Thread-1, ich bin Thread! Mein Name ist Thread-0, ich bin Thread! Mein Name ist Thread-3, ich bin Thread! Mein Name ist Thread-6, ich bin Thread! Mein Name ist Thread-7, ich bin Thread! Mein Name ist Thread-4, ich bin Thread! Mein Name ist Thread-5, ich bin Thread! Mein Name ist Thread-9, ich bin Thread! Mein Name ist Thread-8. Lassen Sie uns 10 Threads ( MyFirstThread- Objekte, die Thread erben) erstellen und sie starten, indem wir für jedes Objekt die Methode start() aufrufen . Nach dem Aufruf der start()- Methode wird die Logik in der run()- Methode ausgeführt. Hinweis: Die Threadnamen sind nicht in der richtigen Reihenfolge. Es ist seltsam, dass sie nicht nacheinander waren:, Thread-1 , Thread-2 und so weiter? Tatsächlich ist dies ein Beispiel für eine Zeit, in der „sequenzielles“ Denken nicht passt. Das Problem besteht darin, dass wir nur Befehle zum Erstellen und Ausführen von 10 Threads bereitgestellt haben. Der Thread-Scheduler, ein spezieller Mechanismus des Betriebssystems, entscheidet über deren Ausführungsreihenfolge. Sein präzises Design und seine Entscheidungsstrategie sind Themen für eine ausführliche Diskussion, auf die wir uns jetzt nicht näher einlassen. Das Wichtigste ist, dass der Programmierer die Ausführungsreihenfolge von Threads nicht kontrollieren kann. Um den Ernst der Lage zu verstehen, versuchen Sie, die main()-Methode im obigen Beispiel noch ein paar Mal auszuführen. Konsolenausgabe beim zweiten Durchlauf: Ich bin Thread! Mein Name ist Thread-0, ich bin Thread! Mein Name ist Thread-4, ich bin Thread! Mein Name ist Thread-3, ich bin Thread! Mein Name ist Thread-2, ich bin Thread! Mein Name ist Thread-1, ich bin Thread! Mein Name ist Thread-5, ich bin Thread! Mein Name ist Thread-6, ich bin Thread! Mein Name ist Thread-8, ich bin Thread! Mein Name ist Thread-9, ich bin Thread! Mein Name ist Thread-7 Konsolenausgabe aus dem dritten Durchlauf: Ich bin Thread! Mein Name ist Thread-0, ich bin Thread! Mein Name ist Thread-3, ich bin Thread! Mein Name ist Thread-1, ich bin Thread! Mein Name ist Thread-2, ich bin Thread! Mein Name ist Thread-6, ich bin Thread! Mein Name ist Thread-4, ich bin Thread! Mein Name ist Thread-9, ich bin Thread! Mein Name ist Thread-5, ich bin Thread! Mein Name ist Thread-7, ich bin Thread! Mein Name ist Thread-8

Durch Multithreading verursachte Probleme

In unserem Beispiel mit Büchern haben Sie gesehen, dass Multithreading sehr wichtige Aufgaben löst und unsere Programme schneller machen kann. Oft um ein Vielfaches schneller. Doch Multithreading gilt als schwieriges Thema. Tatsächlich führt es bei unsachgemäßer Anwendung zu Problemen, anstatt sie zu lösen. Wenn ich sage, dass „Probleme entstehen“, dann meine ich das nicht im abstrakten Sinne. Es gibt zwei spezifische Probleme, die Multithreading verursachen kann: Deadlock und Race Conditions. Deadlock ist eine Situation, in der mehrere Threads auf voneinander gehaltene Ressourcen warten und keiner von ihnen weiter ausgeführt werden kann. Wir werden in den folgenden Lektionen mehr darüber sprechen. Das folgende Beispiel reicht zunächst aus: Multithreading in Java: Was es ist, seine Vorteile und häufige Fallstricke – 4Stellen Sie sich vor, dass Thread-1 mit einem Objekt-1 interagiert und dass Thread-2 mit Objekt-2 interagiert. Darüber hinaus ist das Programm so geschrieben, dass:
  1. Thread-1 beendet die Interaktion mit Objekt-1 und wechselt zu Objekt-2, sobald Thread-2 die Interaktion mit Objekt-2 beendet und zu Objekt-1 wechselt.
  2. Thread-2 beendet die Interaktion mit Objekt-2 und wechselt zu Objekt-1, sobald Thread-1 die Interaktion mit Objekt-1 beendet und zu Objekt-2 wechselt.
Selbst ohne ein tiefes Verständnis von Multithreading können Sie leicht erkennen, dass nichts passieren wird. Die Threads werden niemals die Plätze tauschen und ewig aufeinander warten. Der Fehler scheint offensichtlich, ist es aber in Wirklichkeit nicht. Das geht ganz einfach in einem Programm. In den folgenden Lektionen werden wir Beispiele für Code betrachten, der einen Deadlock verursacht. Quora hat übrigens ein tolles Beispiel aus der Praxis , das erklärt, was ein Deadlock istIst. „In einigen Bundesstaaten Indiens verkaufen sie Ihnen kein landwirtschaftliches Land, es sei denn, Sie sind ein registrierter Landwirt.“ Allerdings werden Sie nicht als Landwirt registriert, wenn Sie kein landwirtschaftliches Land besitzen.“ Großartig! Was können wir sagen?! :) Lassen Sie uns nun über die Rennbedingungen sprechen. Eine Race Condition ist ein Entwurfsfehler in einem Multithread-System oder einer Multithread-Anwendung, bei dem der Betrieb des Systems oder der Anwendung von der Reihenfolge abhängt, in der Teile des Codes ausgeführt werden. Denken Sie an unser Beispiel, in dem wir Threads gestartet haben:

public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("Thread executed: " + getName());
   }
}

public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {

           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
Stellen Sie sich nun vor, dass das Programm dafür verantwortlich ist, einen Roboter zu betreiben, der Essen kocht! Thread-0 holt Eier aus dem Kühlschrank. Thread-1 schaltet den Herd ein. Thread-2 holt eine Pfanne und stellt sie auf den Herd. Thread-3 zündet den Herd an. Thread-4 gießt Öl in die Pfanne. Thread-5 zerbricht die Eier und schüttet sie in die Pfanne. Thread-6 wirft die Eierschalen in den Mülleimer. Thread-7 nimmt die gekochten Eier vom Brenner. Thread-8 legt die gekochten Eier auf einen Teller. Thread-9 spült das Geschirr. Sehen Sie sich die Ergebnisse unseres Programms an: Thread ausgeführt: Thread-0 Thread ausgeführt: Thread-2 Thread ausgeführt Thread-1 Thread ausgeführt: Thread-4 Thread ausgeführt: Thread-9 Thread ausgeführt: Thread-5 Thread ausgeführt: Thread-8 Thread ausgeführt: Thread-7 Thread ausgeführt: Thread-3 Ist das eine Comedy-Routine? :) Und das alles, weil die Arbeit unseres Programms von der Ausführungsreihenfolge der Threads abhängt. Bei der kleinsten Verletzung der vorgeschriebenen Reihenfolge verwandelt sich unsere Küche in eine Hölle und ein verrückter Roboter zerstört alles um sie herum. Dies ist auch ein häufiges Problem bei der Multithread-Programmierung. Davon wird man mehr als einmal hören. Zum Abschluss dieser Lektion möchte ich ein Buch über Multithreading empfehlen. Multithreading in Java: Was es ist, seine Vorteile und häufige Fallstricke – 6„Java Concurrency in Practice“ wurde 2006 geschrieben, hat aber nicht an Relevanz verloren. Es widmet sich der Multithread-Java-Programmierung – von den Grundlagen bis zu den häufigsten Fehlern und Antimustern. Wenn Sie sich eines Tages dazu entschließen, ein Multithreading-Guru zu werden, ist dieses Buch ein Muss. Wir sehen uns in den nächsten Lektionen! :) :)
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION