Informatik B - Objektorientierte Programmierung in Java. Vorlesung 21: Threads 2. Inhalt

Ähnliche Dokumente
Parallele Prozesse. Prozeß wartet

Thread-Synchronisation in in Java. Threads Wechselseitiger Ausschluss Bedingte Synchronisation Beispiel: Warteschlangen

Praktikum aus Softwareentwicklung 2, Stunde 5

Informatik B. Vorlesung 8 Synchronisierung von Threads. Dr. Ralf Kunze

Dr. Monika Meiler. Inhalt

Übung zu Grundlagen der Betriebssysteme. 10. Übung

Zur Erinnerung: Threads. Threadverwaltung. Threads: Prioritäten. Beispiel Flugbuchungsprogramm. Nichtdeterminismus

Nebenläufigkeit mit Java

Betriebssysteme. G: Parallele Prozesse. (Teil B: Klassische Problemstellungen, Mutual Exclusion, kritische Regionen)

parallele Prozesse auf sequenziellen Prozessoren Ein Process ist ein typisches Programm, mit eigenem Addressraum im Speicher.

Verteilte Systeme CS5001

Thread-Konzept in objektorientierten Programmiersprachen. Threads. Threads in Java

Info B VL 16: Monitore und Semaphoren

Ausnahmebehandlung in Java

Leser-Schreiber-Realisierung mit Semaphoren

Prozesszustände (1a)

Synchronisation in Java. Invisible Web

Nebenläufige Programmierung in Java: Threads

5. Threads, Serverprozesse und Benachrichtigungen

Motivation. Informatik B - Objektorientierte Programmierung in Java. Vorlesung 20: Threads. Inhalt. Ein Beispiel zur Motivation

Aufgabenblatt 8 Musterlösung

Lebenszyklus von Threads

OOP: Nebenläufigkeiten Threads. Dipl.-Inform. Arnold Willemer

Beispiel für überladene Methode

Betriebssysteme. Wintersemester Kapitel 2 Prozess und Threads. Patrick Kendzo

Parallele Prozesse Prozeß Parallele Prozesse verzahnte Prozesse Nebenläufige Prozesse: Threads Vorlesung Software-Entwicklung / Folie 131 Ziele:

Programmieren II. Verklemmungen. Vorlesung 10. Handout S. 1. Dr. Klaus Höppner. Hochschule Darmstadt Sommersemester Deadlocks.

Softwaretechnik 1 Übung 5

Nebenläufigkeit mit Java

Informatik II. Semesterklausur

Einführung in die Programmierung Blockkurs Java

Ausgewählte Implementierungsprobleme

Gegenseitiger Ausschluss 102

Java Concurrency Utilities

12. Threads in Java. Sequentielle Abarbeitung (2) Beispiel: Thread (1) Sequentielle Abarbeitung (1)

Einführung Verteilte Systeme - Java Threads I -

9. Vorlesung Betriebssysteme

Programmierung mit Threads in Java

Echtzeitanwendungen mit Java Real Time Specification for Java

Betriebssysteme G: Parallele Prozesse (Teil A: Grundlagen)

Das Monitorkonzept Brinch-Hansen

9. Foliensatz Betriebssysteme

Prozesse. Prozesse sind Programme. Prozesse können aus Unterprozessen bestehen. Prozesshierarchie Unterprozesse Threads

Java Schulung (Java 2 Java Development Kit 5 / 6)

Was machen wir heute? Betriebssysteme Tutorium 3. Organisatorisches. Prozesskontrollblock (PCB) Programmieraufgaben. Frage 3.1.a

Versuchsziele Konzepte der parallelen Programmierung am Beispiel von Threads anwenden können. Einbau von Kontrollmechanismen mittels Semaphore.

Nebenläufigkeit in Java. Prof. Dr. Margarita Esponda

Monitore. Klicken bearbeiten

Nebenläufige und verteilte Programme CS2301

Sequentielle Programm- / Funktionsausführung innerhalb eines Prozesses ( thread = Ausführungsfaden )

Aufgaben zum Thema Verklemmungen

Systeme I: Betriebssysteme Kapitel 4 Prozesse. Maren Bennewitz

Nebenläufige Programmierung I

Systeme I: Betriebssysteme Kapitel 4 Prozesse. Wolfram Burgard

16. Parallelität: Threads

Pthreads. David Klaftenegger. Seminar: Multicore Programmierung Sommersemester

Klausurvorbereitung VS1 (Prof. Brecht) (B0rg Edition)

Verklemmungen - Deadlocks

Parallele und verteilte Anwendungen in Java

Rainer Oechsle. Parallele und verteilte. Anwendungen in Java. 4., neu bearbeitete Auflage. Mit 165 Listings, 5 Tabellen und 71 HANSER

Informatik 12 Kapitel 2 - Kommunikation und Synchronisation von Prozessen

Transkript:

Universität Osnabrück 1 wait und notify 3 - Objektorientierte Programmierung in Java Vorlesung 21: Threads 2 SS 2006 Prof. Dr. F.M. Thiesing, FH Osnabrück Neben dem Monitorkonzept stehen mit den Methoden wait und notify der Klasse Object noch weitere Synchronisationsprimitive zur Verfügung. Zusätzlich zu der bereits erwähnten Sperre, die einem Objekt zugeordnet ist, besitzt das Objekt nämlich auch noch eine Warteliste. Dabei handelt es sich um eine (möglicherweise leere) Menge von Threads, die auf ein Ereignis warten, um fortgesetzt werden zu können. Inhalt 2 wait und notify 4 Threads 2 Synchronisation mit wait und notify Producer/Consumer-Beispiele Lebenszyklus eines Threads Probleme mit Threads Deadlocks Race Condition Ergänzungen synchronized Thread-Namen yield() Priorität Dämonen Sowohl wait als auch notify dürfen nur aufgerufen werden, wenn das Objekt bereits gesperrt ist, also nur innerhalb eines synchronized-blocks für dieses Objekt. Ein Aufruf von wait nimmt die bereits gewährte Sperre (temporär) zurück und stellt den Thread, der den Aufruf von wait verursachte, in die Warteliste des Objekts. Dadurch wird er unterbrochen und im Scheduler als wartend markiert. Ein Aufruf von notify weckt einen (beliebigen) Thread aus der Warteliste des Objekts und führt ihn dem normalen Scheduling zu. Danach versucht der Thread, den Monitor zu belegen, um seine unterbrochene Aufgabe im synchronized-block fortzusetzen.

Einsatz von wait und notify: Producer/Consumer 5 Einsatz von wait und notify: Producer/Consumer 7 Beispiel: Listing2213.java Ein Prozess arbeitet dabei als Produzent, der Fließkommazahlen»herstellt«, und ein anderer als Konsument, der die produzierten Daten»verbraucht«. Die Kommunikation zwischen beiden erfolgt über ein gemeinsam verwendetes Vector-Objekt, das die produzierten Elemente zwischenspeichert und als Monitor für die wait-/notify-aufrufe dient. Da die Wartezeit zufällig ausgewählt wird, kann es durchaus dazu kommen, dass der Produzent eine größere Anzahl an Elementen anhäuft, die der Konsument noch nicht abgeholt hat. Da der Konsumenten-Thread nur dann sinnvoll arbeiten kann, wenn auch Daten im Lager vorhanden sind, reicht es nicht aus, das gleichzeitige Ablaufen von Entfernen und Hinzufügen über synchronized zu verhindern. Der Konsumenten-Thread würde sonst regelmäßig versuchen, aus dem leeren Lager Daten zu entnehmen. Man benötigt also eine Möglichkeit, im Falle eines leeren Puffers den Konsumenten-Thread auf das Eintreffen neuer Daten warten zu lassen. Dies erreicht man mit der Methode wait. Producer/Consumer 6 Beispiel: P/C (1) 8 Ein Thread arbeitet als Produzent, der Fließkommazahlen»herstellt«, und ein anderer als Konsument, der die produzierten Daten»verbraucht«. Die Kommunikation zwischen beiden erfolgt über ein gemeinsam verwendetes Vector-Objekt, das die produzierten Elemente zwischenspeichert: das Lager. Diese Referenz auf das Lager wird als Monitor zum Sperren des exklusiven Zugriffs auf das Lager verwendet. ProducerComsumer.java while (true) { s = "Wert "+Math.random(); synchronized (v) { v.addelement(s); System.out.println("Produzent erzeugte "+s); v.notify();... while (true) { synchronized (v) { while (v.size() < 1) { try { v.wait(); catch (InterruptedException e) { //nichts v.removeelementat(0);... Producer Consumer

Funktionsweise von notify 9 wait() vs. sleep() 11 notify weckt einen beliebigen Thread aus der Warteliste des Objekts, aber nicht einen bestimmten. Der aufgeweckte Thread kann solange nicht im synchronisierten Block fortfahren bis der darin befindliche Thread den Monitor abgibt. Danach versucht er (gleichberechtigt mit anderen Threads) den Monitor zu ergattern. Insbesondere genießt der gerade aufgeweckte Thread keinerlei Vorzugsbehandlung. Es ist wichtig, dass der Konsument mit wait() darauf wartet, dass der Puffer befüllt wird, denn dadurch gibt er die Sperre frei. Würde der Konsument statt dessen Thread.sleep() ausführen, würde er mit dem Monitior in der Hand schlafen und die Sperre nicht frei geben: Der Produzent könnte das Lager nicht befüllen und bis in alle Ewigkeit darauf warten. Beispiel: ProducerConsumerMitSleep.java Lebenszyklus eines Threads 10 Definition: Deadlock 12 new erzeugt start() interrupt() rechenwillig notify() schlafend yield() Scheduler wartend Eine Situation in der Prozessausführung, in der zwei oder mehr Prozesse nicht weiterarbeiten können, weil jeder darauf wartet, dass mindestens ein anderer etwas bestimmtes erledigt. Deadlock = Verklemmung des Prozesses sleep() laufend wait() run() zu Ende oder stop() beendet

Beispiel: Deadlock im Verkehr 13 Standardbeispiel: Dining Philosophers 15 5 Philosophen brauchen zum Essen je zwei Gabeln, aber es existieren nur 5. Wenn alle 5 zur Gabel zu ihrer Rechten greifen, entsteht ein Deadlock. Zweites Problem: Aushungern eines Philosophen. Kann mit kritischen Abschnitten nicht verhindert werden. Java erlaubt einem beliebigen Thread, dranzukommen. Entstehung von Deadlocks i.a. 14 Deadlocks können auftreten, wenn jede der folgenden Bedingungen eintritt: 16 Prozess A Prozess B reserviert benötigt Resource X Resource Y 1. Betriebsmittel werden exklusiv von genau einem Prozess belegt oder sind frei (Gabel). 2. Prozesse warten auf die Zuteilung weiterer Betriebsmittel, während sie bereits welche belegen (linke nach rechter Gabel). 3. Betriebsmittel können nicht entzogen werden, sondern werden vom Prozess zurückgegeben (Hinlegen einer Gabel). 4. Es besteht ein Ring aus zwei oder mehr Prozessen, bei dem jeder auf ein von einem anderen belegtes Betriebsmittel wartet (5 Philosophen).

Strategien zur Deadlock-Bekämpfung 17 Beispiel: Erläuterung 19 Erkennen und Auflösen zur Laufzeit Vermeidung: Eine der 4 Bedingungen durch Einschränkung ausschalten. Verhinderung Eine der 4 Bedingungen durch Zusatzinformation ausschalten. 2. Halten und Warten (a) Reserviere alles im voraus. (b) Gib alles vor der nächsten Reservierung zurück. 4. Zyklisches Warten Totale Ordnung auf alle Ressourcen Reservierung nur in bestimmter Reihenfolge (z.b. aufsteigend) notify() Beispiel: P/C (2) 18 Beispiel: Lösung 20 ProducerConsumerLimited.java Ein Produzent und ein Konsument mit einem begrenzten Lager. synchronized (v) { while (v.size() == limit) { try { Producer v.wait(); catch (InterruptedException e) { //nichts v.addelement(s); System.out.println(" Produzent erzeugte "+s); v.notify(); ProducerConsumerLimitedWithoutDeadlock.java while (true) { synchronized (v) { while (v.size() < 1) { Consumer try { v.wait(); catch (InterruptedException e) { //nichts System.out.print( "Konsument fand "+(String)v.elementAt(0) ); v.removeelementat(0); System.out.println(" (verbleiben:+v.size()+")"); v.notify();

Beispiel: P/C (3) 21 Beispiel: Erläuterung 23 ManyProducerManyConsumerLimited.java Mehrere Produzenten und mehrere Konsumenten mit begrenztem Lager. Die run-methoden bleiben im Wesentlichen unverändert. Ausschnitt ais main(): Consumer[] c = new Consumer[ANZAHL_CONSUMER]; for (int i = 0; i < ANZAHL_CONSUMER; i++) { c[i] = new Consumer(v, i); c[i].start();... ManyProducerManyConsumerLimited.java Begründung für Deadlock: In der Warteliste befinden sich Konsumenten- und Produzenten-Threads. Durch notify() wird ein beliebiger Thread aus der Warteliste gelöst. Im Beispiel warten bereits die beiden Produzenten und Konsument 1. Konsument 0 leert das Lager, durch sein notify() wird zufällig Konsument 1 aus der Warteliste befreit, aber wegen des leeren Lagers müssen anschließend beide Konsumenten- Threads warten: Alle 4 Threads hängen in der Warteliste. Beispiel: Erläuterung 22 Lösung: notifyall 24 ManyProducerManyConsumerLimited.java Die Synchronisation mit wait() und notify() funktioniert für mehrere Produzenten- und Konsumenten-Threads nicht zuverlässig, sondern es kann ein Deadlock eintreten Beispiel mit 2 Produzenten, 2 Konsumenten, Lagergröße 1: notify holt einen beliebigen Thread aus der Warteliste des Objekts, aber nicht einen bestimmten Aber notifyall holt alle wartenden Threads aus der Warteliste!

Beispiel: P/C (4) 25 Ergänzung: synchronized-methoden 27 ManyProducerManyConsumerLimitedWithoutDeadlock.java run-methoden werden verändert: v.notifyall(); statt v.notify(); Dadurch werden jetzt alle wartenden Threads aus der Warteliste geholt, insbesondere auch solche von der anderen Klasse. D.h. ein Konsument holt sicher einen Produzenten aus der Warteliste, der gebraucht wird, um das Lager wieder zu befüllen, damit ein Konsument weiterarbeiten kann und umgekehrt. Problem: Es müssen zwei Methoden eines Objekts exklusiv bearbeitet werden, nicht nur eine! Lösung: Der Monitor für eine Methode hängt an dem Objekt, auf das die Methode wirkt => auch bei mehreren Methoden, die auf dasselbe Objekt wirken, erfolgt damit ein gegenseitiger Ausschluss. Besitzt ein Thread schon den Monitor eines Objekts - d.h. hat er bereits eine synchronized- Methode betreten -, so kann er dennoch weitere synchronized-methoden desselben Objekts aufrufen. Thread-Probleme: Race-Condition 26 Thread-Namen 28 Eine sog. Race-Condition ergibt sich, wenn das Ergebnis einer Berechnung von der Ausführungsreihenfolge der Prozesse abhängt. Problem: zwei (oder mehr) Threads sollen in bestimmter Reihenfolge auf eine Ressource zugreifen. Dies muss synchronisiert werden und darf nicht vom Zufall des Schedulers abhängen. Thread-Name setzen: Thread th1 = new Thread(); th1.setname("thread 1>>> "); Thread-Name in run() abfragen: System.out.print( Thread.currentThread().getName()); Siehe folgendes Beispiel

yield() 29 Priorität 31 yield = abgeben Durch Aufruf von yield() kann ein Thread selbst und freiwillig den Prozessor abgeben, so dass der Scheduler möglicherweise einem anderen Thread Rechenzeit zuteilt. Beispiel: ThreadYield.java Beispiel: ThreadPriority.java Durch setzen der Prioritäten der beiden Threads auf 6 und 4 wird trotz Thread.yield() zunächst nur der höherpriorisierte ausgeführt. Thread.yield(); Führt dazu, dass die gleichpriorisierten Threads überwiegend abwechselnd drankommen. Priorität 30 Dämon 32 Die Priorität steuert den Scheduler in der Weise, dass bei Vorhandensein mehrerer bereiter Threads diejenigen mit höherer Priorität vor denen mit niedrigerer Priorität ausgeführt werden. Als Parameter kann an setpriority() ein Wert übergeben werden, der zwischen den Konstanten Thread.MIN_PRIORITY und Thread.MAX_PRIORITY liegt. Der Normalwert wird durch die Konstante Thread.NORM_PRIORITY festgelegt. In der aktuellen Version des JDK haben diese Konstanten die Werte 1, 5 und 10. ein im Hintergrund laufender Thread wartet in der Regel auf Aufträge von außen Beispiele: Drucker-Spooling Methoden: public void setdaemon( boolean ) macht einen Thread zum Dämon public boolean isdaemon() gibt an, ob ein Thread ein Dämon ist

Dämonen 33 Um einen Dämon zu erzeugen, muss nach dem Erzeugen, aber vor dem Starten des Threads der Aufruf setdaemon(true) erfolgen. Jedes Java-Programm hat Dämon-Threads, die automatisch von der Laufzeitumgebung gestartet werden. Der wichtigste von ihnen ist der Garbage Collector. Ende eines Java-Prozesses 34 Ein Java-Prozess endet, wenn der letzte nichtdämonische Thread des Java-Prozesses beendet wird. Durch Aufruf von System.exit() lassen sich Prozesse mit laufenden Vordergrund-Threads abbrechen.