{"id":6837,"date":"2015-12-26T07:38:55","date_gmt":"2015-12-26T06:38:55","guid":{"rendered":"https:\/\/www.herr-rau.de\/wordpress\/?p=6837"},"modified":"2023-05-30T11:23:53","modified_gmt":"2023-05-30T09:23:53","slug":"threads-i-allgemeines-und-erstes-java","status":"publish","type":"post","link":"https:\/\/www.herr-rau.de\/wordpress\/2015\/12\/threads-i-allgemeines-und-erstes-java.htm","title":{"rendered":"Threads I &#8211; Allgemeines und erstes Java"},"content":{"rendered":"<div style='text-align:right;'><small>(<a href='https:\/\/www.herr-rau.de\/wordpress\/2015\/12\/threads-i-allgemeines-und-erstes-java.htm#comments'>5 Kommentare.<\/a>)<\/small> <\/div>\n<h3 class=\"wp-block-heading\">Paralleles Arbeiten und die Gr\u00fcnde daf\u00fcr<\/h3>\n\n\n\n<p>Fr\u00fcher, als ich angefangen habe, war das noch einfach: Da hatte ein Computer <em>einen<\/em> Prozessor: So hei\u00dft das Ding, das das eigentliche Rechenarbeiten \u00fcbernimmt, irgendwo tief drinnen im Computer. Un <em>ein<\/em> Prozessor hei\u00dft, dass <em>eine<\/em> Rechen- oder sonstige Aufgabe gleichzeitig bearbeitet werden kann. Und doch sah es auch fr\u00fcher so aus, als k\u00f6nnte der Computer zwei Sachen gleichzeitig machen: ein Lied abspielen <em>und<\/em> gleichzeitig im Textverarbeitungsprogramm die getippten Zeichen einf\u00fcgen. Vom Laden und Speichern und der Mausbewegung gar nicht zu reden.<\/p>\n\n\n\n<p>Das funktioniert so, dass der Prozessor zwischen den verschiedenen Programmen sehr schnell wechselt: Ein paar Dutzend Millisekunden darf das Musikspielprogramm ran, dann wieder die Textverarbeitung, dann wieder das Musikprogramm, und so weiter. So entsteht der Eindruck, dass diese Prozesse gleichzeitig ablaufen.<\/p>\n\n\n\n<p>Bei meinem aktuellen Windows laufen zur Zeit um die sechzig solcher Prozesse ab. Der Taskmanager gibt einem einen \u00dcberblick dar\u00fcber:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"590\" height=\"548\" src=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/threads_prozesse.png\" alt=\"threads_prozesse\" class=\"wp-image-6850\" srcset=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/threads_prozesse.png 590w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/threads_prozesse-150x139.png 150w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/threads_prozesse-550x511.png 550w\" sizes=\"auto, (max-width: 590px) 100vw, 590px\" \/><\/figure>\n\n\n\n<p>Inzwischen haben Computer aber mehr als nur einen Prozessor. Neue kommen mit vier oder acht Prozessoren, und jeder Prozessor kann gleichzeitig und unabh\u00e4ngig von den anderen arbeiten. (Es gibt auch Mischformen, bei denen Prozessoren nur halbwegs unabh\u00e4ngig von einander arbeiten, oder dem Betriebssystem vormachen, es g\u00e4be mehr von ihnen, als eigentlich da sind. Und au\u00dferdem hat inzwischen jede Grafikkarte eigene Prozessoren.)<\/p>\n\n\n\n<p>Das ist gut so. Denn richtig viel schneller werden die Prozessoren seit einigen Jahren nicht mehr. Wenn man die Illusion hat, dass Computer trotzdem schneller werden, dann liegt es daran, dass die Prozessorzahl erh\u00f6ht wird und deshalb mehrere Dinge gleichzeitig erledigt werden k\u00f6nnen.<\/p>\n\n\n\n<p>Aber selbst wenn man 32 Prozessoren hat, und eine regul\u00e4re Rechenaufgabe rechnen will &#8211; etwa das Berechnen der Fakult\u00e4t von 200 000 &#8211; dann dauert das noch ziemlich lange, weil sich trotzdem nur ein Prozessor um diese Rechenaufgabe k\u00fcmmert. Wie viele es sonst noch gibt, ist dann auch egal. (Gut, abgesehen davon, dass generell nicht so viel zwischen Prozessen umgeschaltet werden muss, wenn sie sich auf mehr Prozessoren verteilen k\u00f6nnen.)<\/p>\n\n\n\n<p>Wenn man m\u00f6chte, dass es <em>richtig<\/em> schnell geht mit dem Rechnen, dann muss man die Rechenaufgabe geschickt verteilen auf die zu Verf\u00fcgung stehenden Prozessoren.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Fakult\u00e4tsberechnung mit mehreren Prozessoren<\/h3>\n\n\n\n<p>Fakult\u00e4t schreibt man so: <code>n!<\/code>, und das bedeutet <code>n * (n-1) * (n-2) * (n-3) ... * 1<\/code><br>Als Beispiel: <code>12! = 12*11*10*9*8*7*6*5*4*3*2*1 = 479 001 600<\/code><\/p>\n\n\n\n<p>Es gibt keine Abk\u00fcrzung oder Formel f\u00fcr das Berechnen der Fakult\u00e4t: Wenn ich 200000! ausrechnen m\u00f6chte, muss ich wirklich all diese Multiplikationen durchf\u00fchren. Das wird schnell sehr aufwendig.<\/p>\n\n\n\n<p>Wenn ich zwei Prozessoren habe, kann ich die Arbeit aber auf beide verteilen. Um 12! zu berechnen, rechnet der eine dann<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>2*4*6*8*10*12<\/code><\/pre>\n\n\n\n<p>und der andere rechnet<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1*3*5*7*9*11<\/code><\/pre>\n\n\n\n<p>und am Schluss werden die Ergebnisse multipliziert.<\/p>\n\n\n\n<p>Ich kann das auch auf vier Prozessoren verteilen:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1*5*9<br>2*6*10<br>3*7*11<br>4*8*12<\/code><\/pre>\n\n\n\n<p>Oder sechs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>1*7<br>2*8<br>3*9<br>4*10<br>5*11<br>6*12<\/code><\/pre>\n\n\n\n<p>Dann geht das Rechnen insgesamt schneller, weil ich alle vorhandenen Prozessoren dazu nutze. Auf meinem Rechner dauert da berechnen von 200000! &#8211; eine ziemlich gro\u00dfe Zahl &#8211; ohne Verteilung auf mehrere Rechenstr\u00e4nge 76 Sekunden, mit vier Rechenstr\u00e4ngen 12 1\/2 Sekunden, mit acht Str\u00e4ngen gut 10 Sekunden. (Aber nat\u00fcrlich laufen parallel noch viele weitere Prozesse auf meinem Rechner<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Prozesse und Threads<\/h3>\n\n\n\n<p>Wenn auf einem Rechner mit <em>einem<\/em> Prozessor <em>vier<\/em> Programme laufen, dann muss immer wieder zwischen diesen vier Programmen umgeschaltet werden. Das ist aufwendig. Libre Office ist so ein Programm, Firefox ist so ein Programm, iTunes ist so ein Programm. Die laufen im Moment bei mir alle, wenn auch wahrscheinlich auf unterschiedlichen Prozessoren. Das sind sogenannte schwergewichtige Prozesse.<\/p>\n\n\n\n<p>Und dann gibt es sogenannte leichtgewichtige Prozesse, die hei\u00dfen auch: Threads. Ein Programm (wie Firefox) l\u00e4sst gleichzeitig viele Threads laufen. Das Umschalten zwischen Threads ist nicht so aufwendig wie das zwischen schwergewichtigen Prozessen: Die geh\u00f6ren ja alle zum gleichen Programm und benutzen den gleichen Arbeitsspeicherbereich f\u00fcr ihre Daten, so dass dieser Bereich dann beibehalten werden kann. (Libre Office und Firefox dagegen nutzen keinen gemeinsamen Arbeitsspeicherbereich, da hat jeder seinen eigenen. Das hei\u00dft, dass beim Umschalten jeweils auch der ganze Arbeitsspeicherbereich ausgetauscht werden muss.)<\/p>\n\n\n\n<p>Bei dem Firefox-Prozess l\u00e4uft zum Beispiel jeder einzelne Tab als Thread. Das hat einen Nachteil: Wenn ein Thread fehlerhaft ist (wenn ein Tab mit einer Seite Probleme hat und h\u00e4ngen bleibt), muss der ganze Prozess abgebrochen werden &#8211; der ganze Firefox h\u00e4ngt und muss neugestartet werden. Bei Chrome dagegen l\u00e4uft jeder Tab als eigener Prozess: Wenn der dann h\u00e4ngt, muss dieser Prozess abgebrochen werden, aber die anderen Prozesse (Tabs) bleiben unbesch\u00e4digt.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Zust\u00e4nde eines Threads (f\u00fcr den Anfang)<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"118\" src=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_1.png\" alt=\"Threads_1\" class=\"wp-image-6845\" srcset=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_1.png 600w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_1-150x30.png 150w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_1-550x108.png 550w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/figure>\n\n\n\n<p>Wenn ich in einem Programm einen Thread anlege, befindet der sich erstmal im Zustand NEW. Sobald ich ihm dann sage, dass er loslegen soll, befindet er sich im Zustand RUNNABLE: er k\u00f6nnte laufen, wenn er Rechenzeit auf einem Prozessor kriegt. Ob und wann er wirklich zum Rechnen kommt, darauf hat er keinen Einfluss. Das Betriebssystem entscheidet, wer als n\u00e4chster darf. Dazu greift es nach der einen oder anderen Strategie einen rechenbereiten Thread aus dem Pool aller RUNNABLE Threads heraus und l\u00e4sst ihn ein wenig rechnen: Dann ist der Thread im Zustand RUNNING. Und wenn das Betriebssystem nach der einen oder anderen Strategie entscheidet, dass jetzt aber wieder genug ist, dann landet der Thread im Zustand RUNNABLE und wartet, bis er wieder mal dran kommt. Wahrscheinlich ist er irgendwann fertig mit seiner Aufgabe, dann ist sein Zustand TERMINATED.<\/p>\n\n\n\n<p>Die Begriffe orientieren sich in diesem Fall an der Sprache Java; in anderen Umgebungen hei\u00dfen die Zust\u00e4nde vielleicht anders.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Wie ein Thread in Java angelegt wird<\/h3>\n\n\n\n<p>Das geht sehr einfach. Java bringt bereits eine Klasse <code>Thread<\/code> mit, die die wichtigsten Methoden zur Verf\u00fcgung stellt. Man schreibt sich jetzt einfach selber eine Klasse, die von Thread erbt.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"204\" height=\"217\" src=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_Toilettenbenutzer.png\" alt=\"Threads_Toilettenbenutzer\" class=\"wp-image-6879\" srcset=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_Toilettenbenutzer.png 204w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_Toilettenbenutzer-141x150.png 141w\" sizes=\"auto, (max-width: 204px) 100vw, 204px\" \/><\/figure>\n\n\n\n<p>Das einzige, das unsere neue Klasse tun muss ist: die ererbte run-Methode \u00fcberschreiben. Dann sieht die Klasse zum Beispiel so aus:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class Toilettenbenutzer extends Thread {\n  public void run() {\n    System.out.println(getName()+\" benutzt die Toilette.\");\n  }\n}<\/code><\/pre>\n\n\n\n<p>Damit haben wir eine Klasse f\u00fcr jemanden, der einmal aufs Klo geht. Das ist aber langweilig. Also nehmen wir eine Klasse f\u00fcr jemanden, der immer wieder aufs Klo geht:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class Toilettenbenutzer extends Thread {\n  public void run() {\n    while (true) {\n      System.out.println(getName()+\" benutzt die Toilette.\");\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>Oder von mir aus auch 20 mal:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class Toilettenbenutzer extends Thread {\n  int anzahl = 0;\n  public void run() {\n    while (anzahl &lt; 20) {\n      System.out.println(getName()+\" benutzt die Toilette.\");\n      anzahl = anzahl + 1;\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>Die Methode <code>getName<\/code> hat unser <code>Toilettenbenutzer<\/code> von der Klasse <code>Thread<\/code> geerbt. Wenn wir den vorgegebenen Namen \u00e4ndern wollen, k\u00f6nnen wir das mit <code>setName(String)<\/code> tun.<\/p>\n\n\n\n<p>Eine letzte Erg\u00e4nzung: Damit das mit dem Toilettengehen nicht gar so schnell geht, schicken wir unseren Thread jedesmal f\u00fcr zuf\u00e4llige 0.5 bis 1.5 Sekunden schlafen:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class Toilettenbenutzer extends Thread {\n  int anzahl = 0;\n  public void run() {\n    while (anzahl &lt; 20) {\n      System.out.println(getName()+\" benutzt die Toilette.\");\n      anzahl = anzahl + 1;\n      try {\n        sleep( (int) Math.random()*1000+500 );\n      } catch (Exception e) { System.out.println(e); }\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>Neu ist eigentlich nur Zeile 8, aber Java m\u00f6chte, dass diese ererbte Thread-Methode nur innerhalb eines try-catch-Blockes aufgerufen wird, das macht es etwas un\u00fcbersichtlicher.<\/p>\n\n\n\n<p>Ein h\u00e4ufiger Fehler ist es, wenn man jetzt die eben liebevoll angelegte <code>run<\/code>-Methode aufruft. Die wird dann zwar tats\u00e4chlich ausgef\u00fchrt, aber nicht als Thread, sondern regul\u00e4r, also nicht parallel zu anderen Arbeiten. Vielmehr muss man die <code>start<\/code>-Methode der Oberklasse <em>Thread<\/em> aufrufen, und die wiederum ruft die neue <code>run<\/code>-Methode auf &#8211; jetzt aber als Thread.<\/p>\n\n\n\n<p>Jedenfalls haben wir jetzt einen weiteren Zustand von Threads, den des freiwilligen Schlafens:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1199\" height=\"221\" src=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_3.png\" alt=\"Threads_3\" class=\"wp-image-6875\" srcset=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_3.png 1199w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_3-150x28.png 150w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_3-550x101.png 550w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_3-768x142.png 768w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_3-1024x189.png 1024w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_3-660x122.png 660w\" sizes=\"auto, (max-width: 1199px) 100vw, 1199px\" \/><\/figure>\n\n\n\n<p>Zur Wiederholung: Ruft man die Start-Methode auf, wird der Thread in den Zustand RUNNABLE versetzt, und im Zustand RUNNING wird nach und nach die run-Methode ausgef\u00fchrt (mit Unterbrechungen), bis die run-Methode an ihrem Ende angekommen ist und der Thread im Zustand TERMINATED angekommen ist.<\/p>\n\n\n\n<p>Jetzt kann man beliebig viele Objekte vom Typ Toilettenbenutzer erzeugen und starten, und alle gehen unabh\u00e4ngig voneinander immer wieder auf die Toilette.<\/p>\n\n\n\n<p>Damit wir diese Objekte nicht immer wieder von Hand anlegen m\u00fcssen, legen wir eine Starter-Klasse an:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class Starter {\n\n  Toilettenbenutzer t0;\n  Toilettenbenutzer t1;\n  Toilettenbenutzer t2;\n  Toilettenbenutzer t3;\n\n  public Starter() {\n    t0 = new Toilettenbenutzer();\n    t1 = new Toilettenbenutzer();\n    t2 = new Toilettenbenutzer();\n    t3 = new Toilettenbenutzer();\n  }\n\n  void starten() {\n    t0.start();\n    t1.start();\n    t2.start();\n    t3.start();\n  }\n}<\/code><\/pre>\n\n\n\n<p>Und wenn man das dann aufruft, kommt zum Beispiel das heraus:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Thread-3 benutzt die Toilette.\nThread-2 benutzt die Toilette.\nThread-1 benutzt die Toilette.\nThread-4 benutzt die Toilette.\nThread-4 benutzt die Toilette.\nThread-3 benutzt die Toilette.\nThread-1 benutzt die Toilette.\nThread-2 benutzt die Toilette.<\/code><\/pre>\n\n\n\n<p>Schwierig wird es nur, wenn alle dieselbe Toilette benutzen sollen, und das m\u00f6glichst nicht gleichzeitig, sondern nacheinander&#8230;<\/p>\n\n\n\n<p>(<a href=\"https:\/\/www.herr-rau.de\/wordpress\/2015\/12\/threads-ii-java-und-ein-wenig-nebenlaeufigkeit.htm\">Fortsetzung folgt.<\/a> Und bitte gerne auf fachliche Fehler hinweisen.)<\/p>\n\n\n\n<p><strong>Aufgaben:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Legen Sie ein Projekt an, in dem Sie Kopien der Klassen Toilettenbenutzer und Starter anlegen und testen Sie diese.<\/li>\n\n\n\n<li>Legen Sie ein anderes Projekt mit zwei Threads an, wobei der eine die Zahlen von 100 bis 1 ausdruckt und der andere die Zahlen von 1 bis 100, und starten Sie sie gleichzeitig.<\/li>\n\n\n\n<li>Legen Sie vier Threads an, die jeweils wiederholt eine Zeile Ihrer Wahl ausdrucken, und starten Sie sie gleichzeitig.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/ssl-vg03.met.vgwort.de\/na\/875fecf7c6864176910b895bdbbe65db\" alt=\"\"\/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>(5 Kommentare.) Paralleles Arbeiten und die Gr\u00fcnde daf\u00fcr Fr\u00fcher, als ich angefangen habe, war das noch einfach: Da hatte ein Computer einen Prozessor: So hei\u00dft das Ding, das das eigentliche Rechenarbeiten \u00fcbernimmt, irgendwo tief drinnen im Computer. Un ein Prozessor hei\u00dft, dass eine Rechen- oder sonstige Aufgabe gleichzeitig bearbeitet werden kann. Und doch sah es [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":6845,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[25],"tags":[227],"class_list":["post-6837","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-informatik","tag-informatik"],"jetpack_featured_media_url":"https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_1.png","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/posts\/6837","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/comments?post=6837"}],"version-history":[{"count":2,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/posts\/6837\/revisions"}],"predecessor-version":[{"id":58371,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/posts\/6837\/revisions\/58371"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/media\/6845"}],"wp:attachment":[{"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/media?parent=6837"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/categories?post=6837"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/tags?post=6837"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}