Kapitel 22 - Multithreading in Java Inhaltsverzeichnis Inhaltsverzeichnis I. Allgemeines über Threads und Threads in Java II. Die Klasse 'Thread' III. Das Interface 'Runnable' IV. Synchronisation V. Verwaltung von Threads VI. Quellen Kapitel 22 - Multithreading in Java I. Allgemeines über Threads und Threads in Java (1/3) Über Threads Was ist eigentlich ein Thread? ● ● Bedeutung des Wortes 'Thread': Faden, Strang Bedeutung in der Informatik: Ein Thread ist ”Abarbeitungsfaden” eines Prozesses. Was ist der Unterschied zu einem Prozess? ● Ein Prozess ist die Gesamtheit aller von einem Programm zur Laufzeit ausgelösten Vorgänge, ein Thread hingegen nur ein ”Strang” dieser. Wozu Threads? ● Um mehrere Dinge gleichzeitig bzw. quasi gleichzeitig bearbeiten zu können HAW ­ Hamburg ­ OOP in Java 2 Kapitel 22 - Multithreading in Java I. Allgemeines über Threads und Threads in Java (2/3) Über Threads Wozu Threads? (Fortsetzung) ● Um auf die Möglichkeiten moderner Mehrkernprozessoren zurückgreifen zu können. Bestandteile und Aufbau eines Threads ● Jeder Thread hat seinen eigenen Stack, kann jedoch zusammen mit anderen Threads auf gemeinsame Variablen und Methoden des Prozesses zugreifen. HAW ­ Hamburg ­ OOP in Java 3 Kapitel 22 - Multithreading in Java I. Allgemeines über Threads und Threads in Java (3/3) Java und Threads ● ● ● ● ● Threads waren von Beginn an in Java vorgesehen Die Threadfähigkeit des zu Grunde liegenden Betriebssystems spielt bei Java nicht unbedingt eine Rolle, da die Organisation der Threads von der virtuellen Maschine übernommen wird Verfügt das Betriebssystem über Threadfähigkeiten, kann die VM auch diese nutzen Der durch die Nutzung von Threads erzeugte Overhead (Verwaltungsaufwand) ist recht gering und kann meist vernachlässigt werden Alle notwendigen Klassen befinden sich in 'java.lang', sollten also immer verfügbar sein. HAW ­ Hamburg ­ OOP in Java 4 Kapitel 22 - Multithreading in Java II. Die Klasse Thread (1/5) Threadfähigkeit mittels Vererbung ● Um eine Klasse threadfähig zu machen, kann man diese von der Klasse 'Thread' ableiten class TestClass extends Thread { ... ● Startet nun dieser Thread, wird automatisch die Methode 'run()' ausgeführt. Diese ist von 'Thread' geerbt und existiert daher immer. Um eigene Funktionen auszuführen, muss sie jedoch überladen werden. public void run ( ) { ... // Eigene Funktionalität HAW ­ Hamburg ­ OOP in Java 5 Kapitel 22 - Multithreading in Java II. Die Klasse Thread (2/5) Aufruf von Threads ● Achtung: Der neue Thread wird nicht über die Methode 'run()' aufgerufen, sondern über die geerbte Methode 'start()'! // Aufruf einer Instanz von TestClass TestClass test = new TestClass(); test.start(); ● Eine einfache, aber nicht zu empfehlende Methode zum Abbrechen eines Threads ist der Aufruf der Methode 'stop()' (Compiler - Warning). // ”Gewaltsames” Stoppen eines Prozesses test.stop(); HAW ­ Hamburg ­ OOP in Java 6 Kapitel 22 - Multithreading in Java II. Die Klasse Thread (3/4) Abbrechen eines Threads ● ● Möchte man einen laufenden Thread abbrechen, sollte man dort Unterbrechungsanforderungen vorsehen, die z.B. auf ein entsprechendes Signal reagieren. Derartige Signale sind bereits vorgesehen und durch die Klasse 'Thread' implementiert. public void interrupt() ➔ Setzt für den zugehörigen Thread die Unterbrechungsanforderung. public boolean isInterrupted () ➔ Prüft, ob das Unterbrechungsflag gesetzt ist (falls es gesetzt ist, Rückgabewert 'true'). HAW ­ Hamburg ­ OOP in Java 7 Kapitel 22 - Multithreading in Java II. Die Klasse Thread (4/5) Weitere Methoden public static boolean interrupted() ➔ Mit dieser statischen Methode kann man den Status des Flags abfragen ● 'void suspend()' - pausiert einen Thread* ● 'void resume()' - setzt den pausierten Thread fort* ● ● 'boolean isAlive()' - überprüft, ob ein Thread noch aktiv ist (Rückgabe wert 'true' zeigt Aktivität) 'void join()' - wartet, bis ein Thread beendet wurde (kann in der aufrufenden Methode genutzt werden um z.B. auf ein Ergebnis zu warten) * deprecated, nicht empfohlen HAW ­ Hamburg ­ OOP in Java 8 Kapitel 22 - Multithreading in Java II. Die Klasse Thread (5/5) Grafik zu Zuständen von Threads HAW ­ Hamburg ­ OOP in Java 9 Kapitel 22 - Multithreading in Java III. Das Interface 'Runnable' (1/3) Funktion von 'Runnable' ● Möchte man eine Klasse, die von einer anderen Klasse abgeleitet wurde, mit Threadfunktionalität ausstatten, so steht wegen der fehlenden Mehrfachvererbung in Java der oben gezeigte Weg nicht zur Verfügung. ● Stattdessen gibt es das Interface 'Runnable' ● Wie geht man bei Nutzung von 'Runnable' vor? Instanz der Klasse (muss Runnable implementieren), für der Thread erzeugt werden soll, anfordern ➔ Instanz der Klasse 'Thread' anfordern und dem Konstruktor die Referenz der obigen Klasse übergeben ➔ Die Methode 'start()' des Thread - Objektes aufrufen. HAW ­ Hamburg ­ OOP in Java ➔ 10 Kapitel 22 - Multithreading in Java III. Das Interface 'Runnable' (2/3) Funktion von 'Runnable' ● Beispiel: // Instanziierung der eigentlichen // Funktionsklasse FunktionsKlasse A = new FunktionsKlasse(); // Instanziierung des zugehörigen // Threadobjektes Thread B = new Thread(A); // Start des eigentlichen Threads B.start(); HAW ­ Hamburg ­ OOP in Java 11 Kapitel 22 - Multithreading in Java III. Das Interface 'Runnable' (3/3) Wrapper - Klassen ● ➔ ➔ Möchte man bereits bestehende Klassen mit Multithreading - Funktionen versehen, so kann dies durch Erweiterung um eine Wrapper - Klasse geschehen Ein von der alten (zu erweiternden) Klasse abgeleitete Klasse implementiert zusätzlich 'Runnable' Die Methoden, die den Aufruf für die alte Klasse enthalten, werden in der Form überladen, dass sie einen neuen Thread erstellen und in diesem (genauer: in der Methode 'run()' die alten Methoden aufrufen (Stichwort: Schlüsselwort 'super') HAW ­ Hamburg ­ OOP in Java 12 Kapitel 22 - Multithreading in Java IV. Synchronisation (1/4) Problem ● ➔ ➔ ➔ ➔ Greifen 2 Threads z.B. auf einen Datensatz zu, so kann es wegen des ungewissen Laufzeitsverhaltens zu folgender Situation kommen: Thread 1 beginnt auf den Datensatz zu schreiben Thread 2 unterbricht ihn während dessen und überschreibt alle Daten Thread 1 wird fortgesetzt und schreibt den Rest seiner Daten Folge: Der Datensatz kann damit inkonsitent werden (Daten zweier unterschiedlicher Threads gemischt) HAW ­ Hamburg ­ OOP in Java 13 Kapitel 22 - Multithreading in Java IV. Synchronisation (2/4) Monitore ● ➔ Ein Lösungsansatz für das beschriebene Problem ist, kritische Bereiche von Threads (hier: das Schreiben der Datensätze) ”ununterbrechbar” zu machen Dies geschieht durch das Schlüsselwort 'synchronized', welches auf verschiedene Art für Objekte aufgerufen werden kann Will man z.B. einen bestimmten Block einer Methode sperren: synchronized ( getClass() ){ /* kritischer Code */ }; ➔ Oder zum Sperren einer ganzen Methode public synchronized void methode () { /* Methodencode*/ }; ➔ HAW ­ Hamburg ­ OOP in Java 14 Kapitel 22 - Multithreading in Java IV. Synchronisation (3/4) 'wait()' und 'notify()' ● ➔ ➔ Ist ein Objekt mit synchronized gesperrt, kann man mit 'wait()' und 'notify()' Einfluss nehmen 'wait()' - entfernt die Sperren temporär wieder und setzt den aufrufenden Thread auf eine Warteliste des Objekts (der aufrufende Thread wird daraufhin pausiert) 'notify()' - aktiviert den wartenden Thread und stellt dessen Sperre wieder her (der mit 'wait()' zurückgestellte Prozess wird also fortgesetzt) HAW ­ Hamburg ­ OOP in Java 15 Kapitel 22 - Multithreading in Java IV. Synchronisation (4/4) Pipes ● ● ● ● Java bietet, um die Kommunikation zwischen einzelnen Threads, wie im vorigen Beispiel, zu vereinfachen das Konzept der Pipes Dabei werden 2 Threads über einen Bytestream miteinander verbunden, wobei ein Thread Daten hineingibt und ein anderer diese Daten ausliest (unidirektional) Konkret wird der Konsument dann aufgerufen, wenn der Buffer des Bytestreams (1024 Bytes) voll ist Um die genaue Synchronisation muss man sich damit nicht mehr kümmern HAW ­ Hamburg ­ OOP in Java 16 Kapitel 22 - Multithreading in Java V. Verwaltung von Threads (1/3) Namen ● ● ● Jeder Thread in Java hat einen Namen (String) Wird kein Name explizit vergeben, so wird dieser vom Kontruktor standardmäßig auf 'Thread ' + Ordnungszahl gesetzt Alternativ kann dem Konstruktor ein Name übergeben werden Ansonsten ist die Änderung des Namens zur Laufzeit möglich mit String getName( ); ● Gibt den Namen des Threads zurück void setName( String name ); ➔ ➔ Setzt den Namen des betreffenden Threads neu HAW ­ Hamburg ­ OOP in Java 17 Kapitel 22 - Multithreading in Java V. Verwaltung von Threads (2/3) Prioritäten ● ● ● ● ● Die Priorität eines Threads hat direkten Einfluss auf seine Behandlung durch den Scheduler Wird nichts anderes definiert, so wird die Priorität des aufrufenden Threads für den neuen Thread genommen Mögliche Werte sind z.B.: ➔ public final static int MIN_PRIORITY = 1 ➔ public final static int NORM_PRIORITY = 5 ➔ public final static int MAX_PRIORITY = 10 Eingestellt werden kann die Priorität mit der Methode ➔ void setPriority ( int Priority ); Auslesen ist mittels der folgenden Methode möglich ➔ int getPriority ( ); HAW ­ Hamburg ­ OOP in Java 18 Kapitel 22 - Multithreading in Java V. Verwaltung von Threads (3/3) Thread - Gruppen ● ● Thread - Gruppen fassen voneinander abhängende Threads zu Gruppen zusammen, für die man gemeinsame Methoden oder Verwaltungsfunktionen nutzen kann Nützlich bei intensiver Nutzung von Threads HAW ­ Hamburg ­ OOP in Java 19 Kapitel 22 - Multithreading in Java VI. Quellen Quellen ● Guido Krüger, Thomas Stark - Handbuch der Java Programmierung ● Wikipedia ● http://www.nt.fh-koeln.de/fachgebiete/inf/diplom Danke für die Aufmerksamkeit HAW ­ Hamburg ­ OOP in Java 20