Ich denke, ich bekomme die Grundlagen des Multi-Threading mit Java. Wenn ich mich nicht irre, nehmen Sie einen großen Job und finden heraus, wie Sie ihn in mehrere (gleichzeitige) Aufgaben aufteilen. Dann implementieren Sie diese Aufgaben entweder als Runnable
s oder Callable
s und senden sie alle an eine ExecutorService
. (Also zunächst, wenn ich mich so irre, fang bitte an, mich zu korrigieren !!! )
Zweitens muss ich mir vorstellen, dass der Code, den Sie in run()
oder call()
implementieren, so "parallelisiert" wie möglich sein muss, mit nicht blockierenden Algorithmen usw. Und dass hier der schwierige Teil ist ( Parallelcode schreiben). Richtig? Nicht korrekt?
Aber das wirkliche Problem, das ich immer noch mit Java-Nebenläufigkeit habe (und ich vermute, Nebenläufigkeit im Allgemeinen), und das ist das wahre Thema dieser Frage, ist:
Wann ist überhaupt überhaupt ein Multithread möglich?
Ich sah ein Beispiel aus einer anderen Frage zu Stack Overflow, wo das Poster die Erstellung mehrerer Threads zum Lesen und Verarbeiten einer riesigen Textdatei vorschlug (das Buch Moby Dick ) und ein Antworter das Multithreading kommentierte zum Zweck des Lesens von der Platte war eine schreckliche Idee. Ihr Argument dafür war, dass Sie mehrere Threads haben, die den Overhead des Kontextwechsels, on top eines bereits langsamen Prozesses (Festplattenzugriff) einführen.
Das hat mich zum Nachdenken gebracht: Welche Klassen von Problemen eignen sich für Multi-Threading, welche Klassen von Problemen sollten immer serialisiert werden? Vielen Dank im Voraus!
Multi-Threading hat zwei Hauptvorteile, IMO:
Hinweis: Das Problem beim Lesen von mehreren Threads von derselben Festplatte besteht darin, dass statt der ganzen sequenziellen Datei die Platte gezwungen wird, bei jedem Kontextwechsel zwischen verschiedenen physischen Speicherorten der Festplatte zu wechseln. Da alle Threads darauf warten, dass das Lesen der Festplatte beendet wird (sie sind IO-gebunden), wird das Lesen langsamer, als wenn ein einzelner Thread alles lesen würde. Aber sobald die Daten im Speicher sind, wäre es sinnvoll, die Arbeit zwischen Threads aufzuteilen.
Das hat mich zum Nachdenken gebracht: Welche Klassen von Problemen sind angemessen? Multi-Threading, welche Klassen von Problemen sollten immer serialisiert werden?
Grundsätzlich sollten CPU-intensive Tasks (die viele Daten verarbeiten, wie z. B. In-Memory-Sortierung) parallelisiert werden (wenn möglich) und I / O-gebundene Tasks sollten sequentiell bleiben (wie Disk-I / O). Dies ist ein allgemeiner Hinweis mit einigen Ausnahmen natürlich.
Das hat mich zum Nachdenken gebracht: Welche Klassen von Problemen eignen sich für Multi-Threading, welche Klassen von Problemen sollten immer serialisiert werden?
Wenn Sie eine grafische Benutzeroberfläche mit Swing-Komponenten erstellen, dauert es manchmal so lange, bis Sie die Aufgaben, die Sie durch Klicken auf eine Schaltfläche ausführen möchten, so lange sperren, bis Sie die GUI während der Ausführung der Aufgabe sperren / p>
Sie führen die Aufgabe also in einem anderen Thread aus, sodass Sie den GUI-Thread (Swing-Worker-Thread) als Reaktion auf die Swing-Komponenten beibehalten können.
Multithreading ist wertvoll für:
Ich bevorzuge es so ....
Threading ist sehr wichtig bei GUI-basierten Anwendungen.
In Java wird die GUI vom Event Dispatcher Thread behandelt. Es ist immer ratsam, das zu behalten UI-Arbeit am Benutzeroberflächenthread und Nicht-UI-Arbeit am Nicht-UI-Thread. Angenommen, Sie drücken eine Taste und dann geht eine HTTP-Anfrage an einen Webserver, die Verarbeitung findet auf dem Server statt, dann antwortet sie mit dem Ergebnis .. Wenn Sie keinen Nicht-UI-Thread erstellen, um diesen Job zu bearbeiten, dann Ihre GUI wird NICHT REAGIEREN, bis die Antwort des Webservers empfangen wird.
Threads sind auch sehr wichtig in Fällen, in denen mehrere Arbeiten gleichzeitig ausgeführt werden sollen. Das beste Beispiel ist OS . Normalerweise kodiere ich meine Lieblingsmusik und höre gleichzeitig im Internet, usw .... Hier ist Multithreading sehr praktisch, wenn es nur einen Thread gäbe, hätten wir uns nie vorstellen können, was wir können mach heute mit OS.
Mehrere Threads über die CPU hinweg werden für die parallele Verarbeitung einer CPU-intensiven Arbeit verwendet.
Im Fall von Java Servlet wird jede Anforderung, die den Server trifft, von einem separaten Thread behandelt, der vom Container bereitgestellt wird.
Parallelität ist auch in bestimmten Algorithmen sehr nützlich. Zum Beispiel arbeite ich gerade daran, ein Programm zu schreiben, das mithilfe eines genetischen Algorithmus die optimale Lösung für ein kompliziertes Problem berechnet. In einem genetischen Algorithmus haben Sie eine Population von Individuen, die alle eine Fitnessfunktion ausführen müssen. Die Durchführung dieser Fitnesstests wird im Allgemeinen völlig unabhängig voneinander sein, und es wird eine Menge von ihnen durchführen (Sie könnten zum Beispiel Bevölkerungsgrößen von Hunderten haben). Die Parallelisierung kann die Geschwindigkeit eines genetischen Algorithmus dramatisch erhöhen, indem die Zeit verkürzt wird, die für die Ausführung aller Fitnessfunktionen benötigt wird.
Hoffentlich gibt Ihnen das eine Vorstellung davon, worauf Leute sich beziehen, wenn sie von 'CPU-intensiven' Aufgaben sprechen, insbesondere weil nicht alle CPU-intensiven Aufgaben leicht parallel gemacht werden können.
99,9% der Threads auf Ihrer Box machen keine CPU-intensive Arbeit. Meine Box hat momentan 1084 Threads und 1% CPU-Auslastung - die 1084 Threads machen überhaupt nichts aus. Sie warten alle, viele auf Signale von anderen Threads, aber vor allem warten viele auf I / O. Der wichtigste und allgegenwärtige Grund für die Verwendung mehrerer Threads in einem präemptiven Multitasking-Betriebssystem besteht darin, die allgemeine I / O-Leistung für eine App zu steigern. Diese Präventivkerne zwingen uns in den Schmerz der Synchronisation, Warteschlangen, Sperren usw. - im Wesentlichen eine andere Designzone, in der eine Anweisung nicht mehr notwendigerweise der anderen folgt. Der Vorteil ist, dass die E / A-Leistung wesentlich besser ist als bei kooperativen Planungssystemen, da alle Threads, die auf einen Treiber für E / A warten, nach der E / A-Vervollständigung sofort bereit gestellt werden können Treiber, der auf einen Hardware-Interrupt reagiert. Async-E / A ändert dies nicht, es verschiebt nur die E / A-Warte auf einen Kernel-Thread-Pool, der Async-Anforderungen auflisten und den Callback-Setup-Benutzer-Thread bereit machen muss, wenn I / O dafür auftritt (während er Benutzercode erzwingt) um zu expliziten State-Maschinen zurückzukehren. Also, welche Klassen von Problemen für Multi-Threading geeignet sind:
1) Überall dort, wo E / A von mehreren Quellen erwartet wird, bei denen die Fertigstellung asynchron erfolgen kann.
2) Wo Threads das App-Design einfacher, schneller und sicherer machen. Wenn 20 "Dinge" gleichzeitig passieren müssen, ist es viel einfacher, apparent "Inline" -Code zu schreiben und es mit 20 Threads auszuführen, als einen State-Machine selbst zu entwickeln, um 20 verschiedene Kontexte zu behandeln. Da sich Threads in einem Prozess Speicher teilen, ist es trivial, riesige Puffer (OK, Pufferreferenzen / Zeiger) in Warteschlangen zu kommunizieren, um z. Kommst Stacks.
3) CPU-intensive Operationen an Multicore-Boxen, insbesondere wo die Datensätze für jeden Thread / Kern für die Cache-Optimierung isoliert werden können.
4) AOB:)
Ohne mehrere Threads und die I / O-Leistung des preemptiven Kernels gäbe es kein BitTorrent, kein Video-Streaming, keine MMP-Spiele, keinen AVI-Player.
Sie könnten jedoch Notepad und MS Word ausführen ...
Tags und Links java multithreading concurrency