Probleme, die Multithreading in Java löst
Im Wesentlichen wurde Java-Multithreading erfunden, um zwei Hauptprobleme zu lösen:-
Führen Sie mehrere Aktionen gleichzeitig aus.
Im obigen Beispiel führten verschiedene Threads (d. h. Familienmitglieder) mehrere Aktionen parallel aus: Geschirr spülen, in den Laden gehen, Sachen zusammenlegen.
Es kann ein eher „Programmierer“-Beispiel gegeben werden. Stellen Sie sich vor, Sie hätten ein Programm mit einer Benutzeroberfläche. Wenn Sie auf die Schaltfläche „Weiter“ klicken, sollten einige Berechnungen im Programm ausgeführt werden und der Benutzer sollte den folgenden Schnittstellenbildschirm sehen. Wenn diese Aktionen nacheinander ausgeführt werden, friert das Programm nach dem Klicken auf die Schaltfläche „Weiter“ einfach ein. Dem Benutzer wird derselbe Bildschirm mit der Schaltfläche „Weiter“ angezeigt, bis alle internen Berechnungen abgeschlossen sind und das Programm den Teil erreicht, an dem mit dem Zeichnen der Schnittstelle begonnen wird.
Nun, lasst uns ein paar Minuten warten!
Wir können unser Programm auch neu erstellen oder, wie Programmierer sagen, „parallelisieren“. Lassen Sie die erforderlichen Berechnungen in einem Thread und das Rendern der Schnittstelle in einem anderen Thread durchführen. Die meisten Computer verfügen hierfür über genügend Ressourcen. In diesem Fall ist das Programm nicht „dumm“ und der Benutzer kann ruhig zwischen den Bildschirmen der Benutzeroberfläche wechseln, ohne sich Gedanken darüber zu machen, was im Inneren passiert. Es stört nicht :)
-
Beschleunigen Sie Berechnungen.
Hier ist alles viel einfacher. Wenn unser Prozessor über mehrere Kerne verfügt und die meisten Prozessoren mittlerweile Multi-Core-Prozessoren sind, kann unsere Aufgabenliste von mehreren Kernen parallel gelöst werden. Wenn wir 1000 Probleme lösen müssen und jedes davon in einer Sekunde gelöst wird, wird ein Kern die Liste natürlich in 1000 Sekunden bewältigen, zwei Kerne in 500 Sekunden, drei in etwas mehr als 333 Sekunden und so weiter.
Thread
. Das heißt, um 10 Threads zu erstellen und auszuführen, benötigen Sie 10 Objekte dieser Klasse. 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 zu starten, müssen wir eine Klasse erstellen und diese von der erben java.lang
. Thread
und überschreiben Sie die darin enthaltene Methode run()
. Letzteres ist sehr wichtig. In der Methode run()
schreiben wir die Logik vor, die unser Thread ausführen muss. Wenn wir nun eine Instanz erstellen MyFirstThread
und ausführen, run()
gibt die Methode eine Zeile mit ihrem Namen an die Konsole aus: Die Methode getName()
gibt den „System“-Namen des Threads aus, der automatisch zugewiesen wird. Aber warum eigentlich „wenn“? Lasst uns erstellen und testen!
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. Wir erstellen 10 Threads (Objekte) MyFirstThread
, die erben, Thread
und starten sie durch Aufrufen der Methode des Objekts start()
. Nach dem Aufruf einer Methode start()
beginnt ihre Methode zu arbeiten run()
und die darin geschriebene Logik wird ausgeführt. Bitte beachten Sie: Die Threadnamen sind nicht in der richtigen Reihenfolge. Es ist ziemlich seltsam, warum wurden sie nicht nacheinander hingerichtet: Thread-0
, Thread-1
, Thread-2
und so weiter? Dies ist genau ein Beispiel dafür, wann standardmäßiges „sequenzielles“ Denken nicht funktionieren wird. Tatsache ist, dass wir in diesem Fall nur Befehle zum Erstellen und Starten von 10 Threads erteilen. In welcher Reihenfolge sie gestartet werden sollen, entscheidet der Thread-Scheduler: ein spezieller Mechanismus innerhalb des Betriebssystems. Wie genau es aufgebaut ist und nach welchem Prinzip es Entscheidungen trifft, ist ein sehr komplexes Thema, auf das wir uns jetzt nicht näher einlassen. Das Wichtigste ist, dass der Programmierer die Reihenfolge der Thread-Ausführung nicht kontrollieren kann. Um den Ernst der Lage zu erkennen, versuchen Sie, die Methode main()
aus dem obigen Beispiel noch ein paar Mal auszuführen. Zweite Konsolenausgabe: I'm 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 Dritte Konsolenausgabe: 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
Probleme, die durch Multithreading entstehen
Im Beispiel mit Büchern haben Sie gesehen, dass Multithreading ganz wichtige Probleme löst und seine Verwendung die Arbeit unserer Programme beschleunigt. In vielen Fällen – oft. Doch nicht umsonst gilt Multithreading als komplexes Thema. Denn bei falscher Anwendung entstehen Probleme, statt sie zu lösen. Wenn ich sage „Probleme schaffen“, meine ich nicht etwas Abstraktes. Es gibt zwei spezifische Probleme, die Multithreading verursachen kann: Deadlock und Race Condition. Deadlock ist eine Situation, in der mehrere Threads auf voneinander belegte Ressourcen warten und keiner von ihnen mit der Ausführung fortfahren kann. Wir werden in zukünftigen Vorlesungen mehr darüber sprechen, aber für den Moment reicht dieses Beispiel aus: Stellen Sie sich vor, dass Thread-1 mit einem Objekt-1 arbeitet und Thread-2 mit Objekt-2. Das Programm ist wie folgt geschrieben:- Thread-1 hört auf, mit Objekt-1 zu arbeiten und wechselt zu Objekt-2, sobald Thread-2 aufhört, mit Objekt 2 zu arbeiten und zu Objekt-1 wechselt.
- Thread-2 hört auf, mit Objekt-2 zu arbeiten und wechselt zu Objekt-1, sobald Thread-1 aufhört, mit Objekt 1 zu arbeiten und zu Objekt-2 wechselt.
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("Выполнен поток " + 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 für den Betrieb eines Roboters verantwortlich ist, der Essen zubereitet! Thread-0 holt die Eier aus dem Kühlschrank. Stream 1 schaltet den Herd ein. Stream-2 holt eine Bratpfanne heraus und stellt sie auf den Herd. Stream 3 entzündet ein Feuer auf dem Herd. Strom 4 gießt Öl in die Pfanne. Stream 5 bricht die Eier und gießt sie in die Bratpfanne. Stream 6 wirft die Muscheln in den Mülleimer. Stream-7 nimmt die fertigen Rühreier vom Herd. Potok-8 legt Rührei auf einen Teller. Stream 9 wäscht Geschirr. Schauen Sie sich die Ergebnisse unseres Programms an: Thread-0 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-7 Thread ausgeführt -3 Thread-6 Thread ausgeführt. Macht das Skript Spaß? :) Und das alles, weil die Funktionsweise unseres Programms von der Reihenfolge abhängt, in der die Threads ausgeführt werden. Beim kleinsten Verstoß gegen die Reihenfolge verwandelt sich unsere Küche in eine Hölle und ein verrückt gewordener Roboter zerstört alles um ihn herum. Dies ist auch ein häufiges Problem bei der Multithread-Programmierung, von dem Sie mehr als einmal hören werden. Zum Abschluss des Vortrags möchte ich Ihnen ein Buch zum Thema Multithreading empfehlen.
GO TO FULL VERSION