In den Java-Tutorials heißt es, dass das Erstellen eines Threads teuer ist. Aber warum genau ist es teuer? Was genau passiert, wenn ein Java-Thread erstellt wird, dessen Erstellung teuer wird? Ich nehme die Aussage als wahr an, aber ich interessiere mich nur für die Mechanik der Thread-Erstellung in JVM.
Thread-Lebenszyklus-Overhead. Das Erstellen und Herunterfahren von Threads ist nicht kostenlos. Der tatsächliche Overhead variiert je nach Plattform, aber die Thread-Erstellung nimmt Zeit in Anspruch, führt zu einer Latenz bei der Anforderungsverarbeitung und erfordert einige Verarbeitungsaktivitäten von JVM und Betriebssystem. Wenn Anforderungen häufig und einfach sind, wie in den meisten Serveranwendungen, kann das Erstellen eines neuen Threads für jede Anforderung erhebliche Rechenressourcen beanspruchen.
Aus der Java-Parallelität in der Praxis
Von Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes und Doug Lea
Print ISBN-10: 0-321-34960-1
quelle
Antworten:
Die Erstellung von Java-Threads ist teuer, da einiges an Arbeit erforderlich ist:
Es ist auch in dem Sinne teuer, dass der Thread Ressourcen bindet, solange er lebt. zB der Thread-Stapel, alle vom Stapel aus erreichbaren Objekte, die JVM-Thread-Deskriptoren, die systemeigenen Thread-Deskriptoren des Betriebssystems.
Die Kosten für all diese Dinge sind plattformspezifisch, aber auf keiner Java-Plattform, auf die ich jemals gestoßen bin, sind sie billig.
Eine Google-Suche ergab für mich einen alten Benchmark , der eine Thread-Erstellungsrate von ~ 4000 pro Sekunde auf einem Sun Java 1.4.1 auf einem 2002er Dual-Prozessor Xeon mit 2002er Vintage Linux angibt. Eine modernere Plattform liefert bessere Zahlen ... und ich kann die Methodik nicht kommentieren ... aber sie gibt zumindest einen Überblick darüber, wie teuer die Erstellung von Threads wahrscheinlich ist.
Das Benchmarking von Peter Lawrey zeigt, dass die Thread-Erstellung heutzutage absolut gesehen erheblich schneller ist, aber es ist unklar, wie viel davon auf Verbesserungen in Java und / oder dem Betriebssystem zurückzuführen ist ... oder auf höhere Prozessorgeschwindigkeiten. Seine Zahlen deuten jedoch immer noch auf eine mehr als 150-fache Verbesserung hin, wenn Sie einen Thread-Pool verwenden und nicht jedes Mal einen neuen Thread erstellen / starten. (Und er macht den Punkt, dass dies alles relativ ist ...)
(Das oben Gesagte setzt "native Threads" anstelle von "grünen Threads" voraus, aber moderne JVMs verwenden aus Leistungsgründen alle native Threads. Grüne Threads sind möglicherweise billiger zu erstellen, aber Sie zahlen in anderen Bereichen dafür.)
Ich habe ein bisschen gegraben, um zu sehen, wie der Stapel eines Java-Threads wirklich zugewiesen wird. Im Fall von OpenJDK 6 unter Linux wird der Thread-Stack durch den Aufruf zugewiesen
pthread_create
, der den nativen Thread erstellt. (Die JVMpthread_create
übergibt keinen vorab zugewiesenen Stapel.)Dann wird innerhalb
pthread_create
des Stapels durch einen Aufrufmmap
Folgendes zugewiesen :Entsprechend bewirkt
man mmap
dasMAP_ANONYMOUS
Flag, dass der Speicher auf Null initialisiert wird.Obwohl es möglicherweise nicht unbedingt erforderlich ist, dass neue Java-Thread-Stapel (gemäß der JVM-Spezifikation) auf Null gesetzt werden, werden sie in der Praxis (zumindest mit OpenJDK 6 unter Linux) auf Null gesetzt.
quelle
malloc()
Funktion, die die JVM möglicherweise verwendet, nicht garantiert, dass der zugewiesene Speicher auf Null gesetzt ist (vermutlich, um genau solche Leistungsprobleme zu vermeiden).mmap()
Aufruf sind copy-on-write auf eine Seite Null zugeordnet, so dass ihre initailisation nicht innerhalb geschiehtmmap()
selbst, sondern wenn die Seiten werden zuerst geschrieben , und dann nur eine Seite an eine Zeit. Das heißt, wenn der Thread mit der Ausführung beginnt, werden die Kosten vom erstellten Thread und nicht vom Ersteller-Thread getragen.Andere haben diskutiert, woher die Kosten für das Einfädeln kommen. Diese Antwort behandelt, warum das Erstellen eines Threads im Vergleich zu vielen Operationen nicht so teuer ist, aber im Vergleich zu Alternativen zur Aufgabenausführung, die relativ kostengünstig sind, relativ teuer ist.
Die naheliegendste Alternative zum Ausführen einer Aufgabe in einem anderen Thread besteht darin, die Aufgabe im selben Thread auszuführen. Dies ist schwer zu verstehen für diejenigen, die davon ausgehen, dass mehr Threads immer besser sind. Die Logik ist, dass die Ausführung der Aufgabe im aktuellen Thread schneller sein kann, wenn der Aufwand für das Hinzufügen der Aufgabe zu einem anderen Thread größer ist als die Zeit, die Sie sparen.
Eine andere Alternative ist die Verwendung eines Thread-Pools. Ein Thread-Pool kann aus zwei Gründen effizienter sein. 1) Es verwendet bereits erstellte Threads. 2) Sie können die Anzahl der Threads einstellen / steuern, um sicherzustellen, dass Sie eine optimale Leistung erzielen.
Das folgende Programm druckt ....
Dies ist ein Test für eine einfache Aufgabe, bei der der Overhead jeder Threading-Option offengelegt wird. (Diese Testaufgabe ist die Art von Aufgabe, die im aktuellen Thread am besten ausgeführt wird.)
Wie Sie sehen können, kostet das Erstellen eines neuen Threads nur ~ 70 µs. Dies kann in vielen, wenn nicht den meisten Anwendungsfällen als trivial angesehen werden. Relativ gesehen ist es teurer als die Alternativen und in einigen Situationen ist ein Thread-Pool oder die Nichtverwendung von Threads eine bessere Lösung.
quelle
Theoretisch hängt dies von der JVM ab. In der Praxis verfügt jeder Thread über eine relativ große Menge an Stapelspeicher (256 KB pro Standard, glaube ich). Darüber hinaus werden Threads als Betriebssystem-Threads implementiert. Das Erstellen dieser Threads erfordert daher einen Betriebssystemaufruf, dh einen Kontextwechsel.
Beachten Sie, dass "teuer" beim Rechnen immer sehr relativ ist. Die Thread-Erstellung ist im Vergleich zur Erstellung der meisten Objekte sehr teuer, aber im Vergleich zu einer zufälligen Festplattensuche nicht sehr teuer. Sie müssen das Erstellen von Threads nicht um jeden Preis vermeiden, aber das Erstellen von Hunderten von Threads pro Sekunde ist kein kluger Schachzug. In den meisten Fällen sollten Sie einen Thread-Pool mit begrenzter Größe verwenden, wenn Ihr Design viele Threads erfordert.
quelle
K
= 1024 undk
= 1000 .;) En.wikipedia.org/wiki/KibibyteEs gibt zwei Arten von Threads:
Richtige Threads : Dies sind Abstraktionen rund um die Threading-Funktionen des zugrunde liegenden Betriebssystems. Die Thread-Erstellung ist daher genauso teuer wie die des Systems - es gibt immer einen Overhead.
"Grüne" Threads : Von der JVM erstellt und geplant, sind diese billiger, aber es tritt kein richtiger Paralellismus auf. Diese verhalten sich wie Threads, werden jedoch im JVM-Thread des Betriebssystems ausgeführt. Sie werden meines Wissens nicht oft verwendet.
Der größte Faktor, den ich beim Overhead der Thread-Erstellung berücksichtigen kann, ist die Stapelgröße, die Sie für Ihre Threads definiert haben. Die Thread-Stapelgröße kann beim Ausführen der VM als Parameter übergeben werden.
Abgesehen davon hängt die Thread-Erstellung hauptsächlich vom Betriebssystem und sogar von der VM-Implementierung ab.
Lassen Sie mich jetzt auf etwas hinweisen: Das Erstellen von Threads ist teuer, wenn Sie 2000 Threads pro Sekunde pro Sekunde Ihrer Laufzeit auslösen möchten. Die JVM ist nicht dafür ausgelegt . Wenn Sie ein paar Stallarbeiter haben, die nicht immer wieder gefeuert und getötet werden, entspannen Sie sich.
quelle
Das Erstellen
Threads
erfordert die Zuweisung einer angemessenen Menge an Speicher, da nicht nur ein, sondern zwei neue Stapel erstellt werden müssen (einer für Java-Code, einer für nativen Code). Durch die Verwendung von Executors / Thread-Pools kann der Overhead vermieden werden, indem Threads für mehrere Aufgaben für Executor wiederverwendet werden .quelle
Der Kern der Frage ist natürlich, was "teuer" bedeutet.
Ein Thread muss einen Stapel erstellen und den Stapel basierend auf der Ausführungsmethode initialisieren.
Es muss Kontrollstatusstrukturen einrichten, dh in welchem Zustand es ausgeführt werden kann, wartet usw.
Es gibt wahrscheinlich viel Synchronisation beim Einrichten dieser Dinge.
quelle