{"id":6858,"date":"2015-12-27T08:24:04","date_gmt":"2015-12-27T07:24:04","guid":{"rendered":"https:\/\/www.herr-rau.de\/wordpress\/?p=6858"},"modified":"2023-05-30T10:50:00","modified_gmt":"2023-05-30T08:50:00","slug":"threads-ii-java-und-ein-wenig-nebenlaeufigkeit","status":"publish","type":"post","link":"https:\/\/www.herr-rau.de\/wordpress\/2015\/12\/threads-ii-java-und-ein-wenig-nebenlaeufigkeit.htm","title":{"rendered":"Threads II &#8211; Java und ein wenig Nebenl\u00e4ufigkeit"},"content":{"rendered":"<div style='text-align:right;'><small>(<a href='https:\/\/www.herr-rau.de\/wordpress\/2015\/12\/threads-ii-java-und-ein-wenig-nebenlaeufigkeit.htm#comments'>1 Kommentare.<\/a>)<\/small> <\/div>\n<p>(<a href=\"https:\/\/www.herr-rau.de\/wordpress\/2015\/12\/threads-i-allgemeines-und-erstes-java.htm\">Fortsetzung von hier.<\/a>) Stehengeblieben waren wir bei einer Klasse Toilettenbenutzer (eine Unterklasse von Thread), deren Objekte in einer Schleife immer und immer wieder auf die Toilette gehen. Und weil es Threads sind, k\u00f6nnen die das alle gleichzeitig und unabh\u00e4ngig von einander. Schwierig wird es nur, wenn alle dieselbe Toilette benutzen sollen, und das m\u00f6glichst nicht gleichzeitig, sondern nacheinander&#8230;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Nebenl\u00e4ufigkeit: Die Notwendigkeit f\u00fcr Synchronisation<\/h3>\n\n\n\n<p>Wenn alle nur <em>eine<\/em> Toilette benutzen sollen, dann brauchen wir erst einmal eine solche Toilette:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class Toilette {   \n  public void benutzen(Toilettenbenutzer t) {\n    System.out.println(t.getName()+\" betritt Toilette.\");\n    System.out.println(t.getName()+\" benutzt Toilette.\");\n    System.out.println(t.getName()+\" spuelt.\");\n    System.out.println(t.getName()+\" waescht Haende.\");\n    System.out.println(t.getName()+\" verlaesst Toilette.\");\n    System.out.println();\n  }    \n}<\/code><\/pre>\n\n\n\n<p>Die Toilette hat eine Methode <code>benutzen<\/code>, der als Argument ein Toilettenbenutzer \u00fcbergeben wird &#8211; eigentlich nur deshalb, damit wir seinen Namen erfragen und ausgeben k\u00f6nnnen, wer jetzt im Moment gerade die Toilette benutzt. Wir m\u00fcssen jetzt nur noch unsere Toilettenbenutzer anpassen, damit die auch wirklich die Toilette benutzen. Dazu kriegen sie ein Referenzattribut vom Typ Toilette, das im Konstruktor gleich belegt wird:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class Toilettenbenutzer extends Thread {\n  Toilette toilette;\n  int anzahl = 0;\n  public Toilettenbenutzer(Toilette t) {\n    toilette = t;\n  }\n  public void run() {\n    while (anzahl &lt; 20) {\n      toilette.benutzen(this);  \/\/\"this\" bezieht sich auf das aktuelle Objekt\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>(Nat\u00fcrlich m\u00fcssen wir auch im Starter eine Toilette anlegen und den Konstruktoren \u00fcbergeben.)<\/p>\n\n\n\n<p>Wenn wir jetzt mit unserem Starter-Objekt eine Reihe von Toilettenbenutzer-Threads anlegen und starten, dann wird das ein heilloses Durcheinander:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Thread-2 betritt Toilette.\nThread-2 benutzt Toilette.\nThread-5 betritt Toilette.\nThread-3 betritt Toilette.\nThread-4 betritt Toilette.\nThread-3 benutzt Toilette.\nThread-5 benutzt Toilette.\nThread-5 spuelt.\nThread-5 waescht Haende.\nThread-5 verlaesst Toilette.\nThread-2 spuelt.\n\nThread-3 spuelt.\nThread-4 benutzt Toilette.\nThread-3 waescht Haende.\nThread-2 waescht Haende.\nThread-3 verlaesst Toilette.<\/code><\/pre>\n\n\n\n<p>Wir m\u00fcssen irgendwie sicherstellen, dass nur einer auf einmal die Toilette benutzen kann. Solche W\u00fcnsche gibt es viele: Beim Durchf\u00fchren von Kontotransaktionen, beim Buchen von Reisen, beim \u00d6ffnen und Schreiben auf Dokumenten m\u00f6chten wir h\u00e4ufig, dass nur einer gleichzeitig heran darf. Der gemeinsam genutzte und zu beobachtende Bereich hei\u00dft <strong>kritischer Bereich<\/strong>. Wenn es solche Bereiche gibt, wenn sich also parallele Prozesse absprechen m\u00fcssen, spricht man von <strong>Nebenl\u00e4ufigkeit.<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">L\u00f6sungsversuch: Semaphore<\/h3>\n\n\n\n<p>Ein Semaphor ist ein Zeichen, das etwa vor einer kritischen Eisenbahnstrecke signalisiert, ob sie gerade befahren werden kann oder nicht. Oder eben ein Besetztzeichen bei einer Toilette. Man sollte meinen, dass man sich so etwas einfach selber programmieren kann:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class Toilette {   \n  int anzahlBenutzer = 0;\n  public void benutzen(Toilettenbenutzer t) {\n    while (anzahlBenutzer&gt;0) {\n      \/\/t muss halt warten\n    }\n    anzahlBenutzer = anzahlBenutzer+1;\n    System.out.println(t.getName()+\" betritt Toilette.\");\n    System.out.println(t.getName()+\" benutzt Toilette.\");\n    System.out.println(t.getName()+\" spuelt.\");\n    System.out.println(t.getName()+\" waescht Haende.\");\n    System.out.println(t.getName()+\" verlaesst Toilette.\");\n    System.out.println();\n    anzahlBenutzer = anzahlBenutzer-1;\n  }\n}<\/code><\/pre>\n\n\n\n<p>Neu ist das Attribut <code>anzahlBenutzer<\/code>, initialisiert mit dem Wert 0. Das ist unser Besetztzeichen: Wenn die Anzahl 0 ist, ist die Toilette frei, wenn die Anzahl 1 ist, ist sie besetzt. (Das k\u00f6nnte man auch mit einem Booleschen Attribut machen, aber so l\u00e4sst sich das sp\u00e4ter leichter erweitern, wenn man einen kritischen Bereich hat, der von zwei oder mehre Threads auf einmal betreten werden darf, aber nicht beliebig vielen.)<\/p>\n\n\n\n<p>Wenn ein Thread die <code>benutzen<\/code>-Methode aufruft, und die Toilette ist besetzt, dann landet er in einer Warteschleife (Zeilen 4-6). Aus der kommt er erst wieder heraus, wenn die Anzahl der Benutzer wieder auf 0 ist. Dann, also ab Zeile 7, wird das Warnsignal um 1 erh\u00f6ht, das Gesch\u00e4ft verrichtet, und am Ende wird das Warnsignal wieder um 1 vermindert, hat also wieder den Wert 0.<\/p>\n\n\n\n<p>Leider funktioniert das aber nicht. Also, wenn man Gl\u00fcck hat, dann schon. Aber wenn man Pech hat, dann fragt Thread 1 gerade, ob die Toilette frei ist und kriegt ein Ja. Und bevor Thread 1 dann den Semaphor auf besetzt schalten kann, fragt Thread 2 an, ob die Toilette frei ist, und kriegt ebenfalls ein Ja. Schon haben wir den Salat. Dazu kommt noch, dass dann m\u00f6glicherweise der eine Thread gerade die Anzahl um 1 erh\u00f6ht und der andere Thread mittenreingr\u00e4tscht und deshalb eine falsche Anzahl gespeichert wird.<\/p>\n\n\n\n<p>Wenn man zum Beispiel vier der Toilettenbenutzer oben und eine Toilette anlegt und die Toilettenbenutzer startet, dann gibt es folgende M\u00f6glichkeiten:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>alles l\u00e4uft bestens und niemand kommt sich in die Quere<\/li>\n\n\n\n<li>zwei oder mehr Benutzer sind mal gleichzeitig in der Toilette, aber die Anzahl der Toilettenbesucher stimmt (sie ist zwischendurch vielleicht mal auf 2, aber ganz am Ende wieder auf 0)<\/li>\n\n\n\n<li>zwei oder mehr Benutzer sind mal gleichzeitig in der Toilette und st\u00f6ren sich beim Erh\u00f6hen oder Erniedrigen der Anzahl der Toilettenbesucher. Dann ist die Anzahl zum Beispiel -1 (wenn eine der Erh\u00f6hungen beim Speichern durch einen anderen Speicher\u00fcbergang \u00fcberschrieben wird und deshalb nicht z\u00e4hlt), und das wiederum hei\u00dft, dass niemand mehr die Toilette betreten kann und alle weiteren Benutzer f\u00fcr immer in der while-Schleife gefangen sind.<\/li>\n<\/ul>\n\n\n\n<p>Am besten l\u00e4sst man zum Ausprobieren jeden Toiletteng\u00e4nger einige hundert Male die Toilette benutzen, und kommentiert die Ausgabezeilen aus, und l\u00e4sst das sleep() weg, dann geht das schneller. Die benutzen-Methode ist dann so kurz, dass sich zwei Threads leicht in die Quere kommen k\u00f6nnen:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">while (anzahlBenutzer&gt;0) {\n  anzahlBenutzer = anzahlBenutzer+1;\n  anzahlBenutzer = anzahlBenutzer-1;\n}<\/pre>\n\n\n\n<p>Wenn die Benutzerzahl 0 am Anfang 0 ist, \u00fcberspringt Thread 1 die Schleife, dann \u00fcberspringt Thread 2 die Schleife, <em>dann<\/em> errechnet Thread 1 den neuen Wert des Semaphoren (n\u00e4mlich 1), dann errechnet Thread 2 den neuen Wert des Semaphoren (n\u00e4mlich 2), dann speichert Thread 2 den errechneten Wert (2), dann speichert Thread 1 den errechneten Wert (1), danach reduzieren beide nacheinander den Semaphor, so dass der auf -1 steht. Bl\u00f6d gelaufen.<\/p>\n\n\n\n<p>Das Grundproblem ist n\u00e4mlich das hier: Bei einem Semaphor muss die \u00dcberpr\u00fcfung seines Zustands (&#8222;Ist das Klo frei?&#8220;) und die \u00c4nderung seines Zustands (&#8222;Ich setze das Zeichen auf besetzt.&#8220;) <em>gleichzeitig<\/em> und jedenfalls ununterbrechbar stattfinden. Und das kann man nicht so einfach selber programmieren. Das muss die Programmiersprache dem Programmierer bereits zur Verf\u00fcgung stellen.<\/p>\n\n\n\n<p>Bei Java geschieht das in Form von Monitoren, die intern mit Semaphoren arbeiten, aber das braucht uns nicht zu interessieren.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Monitore<\/h3>\n\n\n\n<p>&#8222;Monitor&#8220; hei\u00dft urspr\u00fcnglich nicht &#8222;Bildschirm&#8220;, sondern &#8222;Aufseher, Aufpasser&#8220; oder in der Schule &#8222;Klassenordner&#8220;. In Java kann man jedes Objekt zu einem Monitor machen, indem man dem Objekt eine oder mehrere Methoden gibt, denen das Schl\u00fcsselwort <code>synchronized<\/code> vorangestellt ist. F\u00fcr alle synchronisierten Methoden eines Monitorobjekts gilt: nur eine synchronisierte Methode kann gleichzeitig von irgendwem aufgerufen werden. Wenn eine zweite Methode oder die erste Methode noch einmal aufgerufen wird, wird der aufrufende Thread in einen neuen Zustand versetzt: BLOCKED. Und der bleibt solange in diesem Zustand, bis die zuvor aufgerufene synchronisierte Monitor-Methode beendet wurde und der Monitor daf\u00fcr sorgt, dass die blockierte Methode wieder RUNNABLE wird. Wir haben also einen neuen Zustand f\u00fcr Threads:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1199\" height=\"292\" src=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_4.png\" alt=\"Threads_4\" class=\"wp-image-6888\" srcset=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_4.png 1199w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_4-150x37.png 150w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_4-550x134.png 550w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_4-768x187.png 768w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_4-1024x249.png 1024w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/Threads_4-660x161.png 660w\" sizes=\"auto, (max-width: 1199px) 100vw, 1199px\" \/><\/figure>\n\n\n\n<p>Der Code f\u00fcr unsere Toilette sieht daf\u00fcr wieder ganz einfach aus, da wir uns nicht selber um Semaphoren k\u00fcmmern m\u00fcssen:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public class Toilette {   \n  public synchronized void benutzen(Toilettenbenutzer t) {\n    System.out.println(t.getName()+\" betritt Toilette.\"+besetzt);\n    System.out.println(t.getName()+\" benutzt Toilette.\"+besetzt);\n    System.out.println(t.getName()+\" spuelt.\"+besetzt);\n    System.out.println(t.getName()+\" waescht Haende.\"+besetzt);\n    System.out.println(t.getName()+\" verlaesst Toilette.\"+besetzt);\n    System.out.println();\n  }\n}<\/code><\/pre>\n\n\n\n<p>Man kann das anzahlBenutzer-Attribut und dessen \u00c4nderungen beibehalten, dann l\u00e4sst sich leicht \u00fcberpr\u00fcfen, dass diesmal die Z\u00e4hlerei stets stimmt. Und die Ausgaben sind auch nicht mehr gemischt:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Thread-2 betritt Toilette.\nThread-2 benutzt Toilette.\nThread-2 spuelt.\nThread-2 waescht Haende.\nThread-2 verlaesst Toilette.\n\nThread-3 betritt Toilette.\nThread-3 benutzt Toilette.\nThread-3 spuelt.\nThread-3 waescht Haende.\nThread-3 verlaesst Toilette.\n\nThread-2 betritt Toilette.\nThread-2 benutzt Toilette.\nThread-2 spuelt.\nThread-2 waescht Haende.\nThread-2 verlaesst Toilette.<\/pre>\n\n\n\n<p>Die Toilettenbenutzer besuchen die Toilette nicht unbedingt abwechselnd (auf die Reihenfolge der Toilettenbenutzer hat man erst einmal keinen Einfluss), aber jedenfalls sicher strikt hintereinander und nie gleichzeitig.<\/p>\n\n\n\n<p>(<a href=\"https:\/\/www.herr-rau.de\/wordpress\/2015\/12\/threads-iii-erzeuger-verbraucher-und-ein-neuer-zustand.htm\">Fortsetzung folgt.<\/a> Denn etwas recht Schwieriges und ein weiterer Zustand f\u00fcr Threads kommen noch. Korrekturen bitte gerne als Kommentar.)<\/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 mit den Klassen Starter, Toilette und Toilettenbenutzer an und testen Sie es. Testen Sie es einmal mit einem Monitor (mit synchronisierten Methoden) und einmal ohne das Schl\u00fcsselwort <code>synchronized<\/code>.<\/li>\n\n\n\n<li>Legen Sie ein neues Projekt an mit den Klassen <code>Starter<\/code>, <code>Bankkonto<\/code>, <code>Einzahler<\/code> und <code>Abheber<\/code> an.<br>Das Konto erh\u00e4lt ein Attribut <code>int kontostand<\/code> mit dem Startwert 0 und die (synchronisierten) Methoden <code>einzahlen(int)<\/code> und <code>auszahlen(int)<\/code>. Diesen Methoden wird jeweils eine positive Ganzzahl \u00fcbergeben und der Wert des Attributs <code>kontostand<\/code> entsprechend erh\u00f6ht oder vermindert.<br>Einzahler und Abheber erhalten ein Referenzattribut vom Typ <code>Bankkonto<\/code>, das wie im Beispiel oben im Konstruktor initialisiert wird. Jeder Einzahler soll zwnazigmal 10 einzahlen, jeder Abheber soll zwanzig 10 abheben.<br>Die Starter-Klasse soll f\u00fcr Sie ein Konto, einen Abheber, einen Verbraucher anlegen und starten.<br>Am Schluss m\u00fcsste der Kontostand wieder bei 0 sein. Testen Sie das. Testen Sie das auch mit jeweils zehntausend statt mit zehn Abbuchvorvorg\u00e4ngen.<\/li>\n\n\n\n<li>Testen Sie das einige Male ohne das Schl\u00fcsselwort <code>synchronized<\/code>, und schauen Sie, ob der Kontostand am Ende wieder 0 ist. Dazu sollten Sie mit zwanzigtausend statt mit zwanzig Buchungen arbeiten. (Wenn Sie mit <code>sleep()<\/code> arbeiten, sollten Sie das dazu auskommentieren. Sonst dauert das zu lange.)<\/li>\n\n\n\n<li>Testen Sie das alles mit zwei Einzahler- und zwei Abheber-Objekten.<\/li>\n\n\n\n<li>Denken Sie sich ein eigenes Beispiel aus, das notwendigerweise mit einem Monitor\/synchronisierten Methoden arbeitet, und implementieren Sie es.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/ssl-vg03.met.vgwort.de\/na\/958f9b465a7f4a82a461aa1dce71d0f7\" alt=\"\"\/><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>(1 Kommentare.) (Fortsetzung von hier.) Stehengeblieben waren wir bei einer Klasse Toilettenbenutzer (eine Unterklasse von Thread), deren Objekte in einer Schleife immer und immer wieder auf die Toilette gehen. Und weil es Threads sind, k\u00f6nnen die das alle gleichzeitig und unabh\u00e4ngig von einander. Schwierig wird es nur, wenn alle dieselbe Toilette benutzen sollen, und das [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":6875,"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-6858","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_3.png","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/posts\/6858","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=6858"}],"version-history":[{"count":3,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/posts\/6858\/revisions"}],"predecessor-version":[{"id":58369,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/posts\/6858\/revisions\/58369"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/media\/6875"}],"wp:attachment":[{"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/media?parent=6858"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/categories?post=6858"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/tags?post=6858"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}