Nebenläufige Programmierung in Java: Threads Wahlpflicht: Fortgeschrittene Programmierung in Java Jan Henke HAW Hamburg 10. Juni 2011 J. Henke (HAW) Threads 10. Juni 2011 1 / 18 Gliederung 1 Grundlagen Wiederholung: Threadgrundlagen Einfache Threads in Java 2 Fortgeschrittene Konzepte Executor Synchronisation J. Henke (HAW) Threads 10. Juni 2011 2 / 18 Gliederung 1 Grundlagen Wiederholung: Threadgrundlagen Einfache Threads in Java 2 Fortgeschrittene Konzepte Executor Synchronisation J. Henke (HAW) Threads 10. Juni 2011 3 / 18 Definition einen Threads Definition Ein Thread ist ein Programmteil, welcher parallel zum dem übrigen Programm ausgeführt wird, über einen eigenen Stack verfügt und außer diesem alle Ressourcen mit dem restlichen Prozess teilt. J. Henke (HAW) Threads 10. Juni 2011 4 / 18 Definition einen Threads Definition Ein Thread ist ein Programmteil, welcher parallel zum dem übrigen Programm ausgeführt wird, über einen eigenen Stack verfügt und außer diesem alle Ressourcen mit dem restlichen Prozess teilt. Zu beachten ist: Dieselbe Codezeile kann simultan von mehreren Threads ausgeführt werden. J. Henke (HAW) Threads 10. Juni 2011 4 / 18 Definition einen Threads Definition Ein Thread ist ein Programmteil, welcher parallel zum dem übrigen Programm ausgeführt wird, über einen eigenen Stack verfügt und außer diesem alle Ressourcen mit dem restlichen Prozess teilt. Zu beachten ist: Dieselbe Codezeile kann simultan von mehreren Threads ausgeführt werden. Variablen auf dem Heap sind im Allgemeinen nicht threadspezfisch. J. Henke (HAW) Threads 10. Juni 2011 4 / 18 Vorteil von Multithreaded Anwendungen Bessere Ausnutzung von Wartepausen, kein „busy waiting” J. Henke (HAW) Threads 10. Juni 2011 5 / 18 Vorteil von Multithreaded Anwendungen Bessere Ausnutzung von Wartepausen, kein „busy waiting” I insbesondere bei I/O-Operationen wichtig J. Henke (HAW) Threads 10. Juni 2011 5 / 18 Vorteil von Multithreaded Anwendungen Bessere Ausnutzung von Wartepausen, kein „busy waiting” I insbesondere bei I/O-Operationen wichtig Bessere Ausnutzung heutiger symmetrischer Multiprozessorsysteme (SMP) J. Henke (HAW) Threads 10. Juni 2011 5 / 18 Vorteil von Multithreaded Anwendungen Bessere Ausnutzung von Wartepausen, kein „busy waiting” I insbesondere bei I/O-Operationen wichtig Bessere Ausnutzung heutiger symmetrischer Multiprozessorsysteme (SMP) Entkoppelung verschiedener Programmteile möglich, z.B.: J. Henke (HAW) Threads 10. Juni 2011 5 / 18 Vorteil von Multithreaded Anwendungen Bessere Ausnutzung von Wartepausen, kein „busy waiting” I insbesondere bei I/O-Operationen wichtig Bessere Ausnutzung heutiger symmetrischer Multiprozessorsysteme (SMP) Entkoppelung verschiedener Programmteile möglich, z.B.: I asynchrone Reaktion auf Events J. Henke (HAW) Threads 10. Juni 2011 5 / 18 Vorteil von Multithreaded Anwendungen Bessere Ausnutzung von Wartepausen, kein „busy waiting” I insbesondere bei I/O-Operationen wichtig Bessere Ausnutzung heutiger symmetrischer Multiprozessorsysteme (SMP) Entkoppelung verschiedener Programmteile möglich, z.B.: I I asynchrone Reaktion auf Events Erzeuger-Verbraucher Muster J. Henke (HAW) Threads 10. Juni 2011 5 / 18 Gliederung 1 Grundlagen Wiederholung: Threadgrundlagen Einfache Threads in Java 2 Fortgeschrittene Konzepte Executor Synchronisation J. Henke (HAW) Threads 10. Juni 2011 6 / 18 Erzeugung eines neuen Threads Welche Ausgabe ergibt das folgende Codesegment? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 R u n n a b l e toRun = new R u n n a b l e ( ) { @Override p u b l i c void run ( ) { f o r ( i n t i = 0 ; i < 1 0 ; i ++) { S y st e m . o u t . p r i n t l n ( i ) ; } } }; Thread thread1 Thread thread2 t h r e a d 1 = new T h r e a d ( toRun ) ; . start () ; t h r e a d 2 = new T h r e a d ( toRun ) ; . start () ; J. Henke (HAW) Threads 10. Juni 2011 7 / 18 Erzeugung eines neuen Threads Welche Ausgabe ergibt das folgende Codesegment? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1 R u n n a b l e toRun = new R u n n a b l e ( ) { @Override p u b l i c void run ( ) { f o r ( i n t i = 0 ; i < 1 0 ; i ++) { S y st e m . o u t . p r i n t l n ( i ) ; } } }; Thread thread1 Thread thread2 t h r e a d 1 = new T h r e a d ( toRun ) ; . start () ; t h r e a d 2 = new T h r e a d ( toRun ) ; . start () ; 01201345678923456789 J. Henke (HAW) Threads 10. Juni 2011 7 / 18 Thread implementiert Runnable Die Klasse Thread implementiert selbst das Interface Runnable J. Henke (HAW) Threads 10. Juni 2011 8 / 18 Thread implementiert Runnable Die Klasse Thread implementiert selbst das Interface Runnable I Alle Konstruktoren sind doppelt vorhanden, jeweils mit und ohne Runnable als Argument J. Henke (HAW) Threads 10. Juni 2011 8 / 18 Thread implementiert Runnable Die Klasse Thread implementiert selbst das Interface Runnable I I Alle Konstruktoren sind doppelt vorhanden, jeweils mit und ohne Runnable als Argument Thread erweitern und run() überschreiben J. Henke (HAW) Threads 10. Juni 2011 8 / 18 Grundlegende Steuerung Die Klasse java.lang.Thread bietet eine Reihe von Methoden an, um das Verhalten des (aktuellen) Threads zu beinflussen: J. Henke (HAW) Threads 10. Juni 2011 9 / 18 Grundlegende Steuerung Die Klasse java.lang.Thread bietet eine Reihe von Methoden an, um das Verhalten des (aktuellen) Threads zu beinflussen: Die statischen Methoden beinflussen den aktuellen Thread, welcher den Code aktuell ausführt, dazu zählen unter anderem: J. Henke (HAW) Threads 10. Juni 2011 9 / 18 Grundlegende Steuerung Die Klasse java.lang.Thread bietet eine Reihe von Methoden an, um das Verhalten des (aktuellen) Threads zu beinflussen: Die statischen Methoden beinflussen den aktuellen Thread, welcher den Code aktuell ausführt, dazu zählen unter anderem: I Thread.currentThread() liefert die Referenz auf der aktuellen Thread. J. Henke (HAW) Threads 10. Juni 2011 9 / 18 Grundlegende Steuerung Die Klasse java.lang.Thread bietet eine Reihe von Methoden an, um das Verhalten des (aktuellen) Threads zu beinflussen: Die statischen Methoden beinflussen den aktuellen Thread, welcher den Code aktuell ausführt, dazu zählen unter anderem: I I Thread.currentThread() liefert die Referenz auf der aktuellen Thread. Thread.yield() gibt den Rest der aktuell zugeteilten Rechenzeit ab. (Verhalten ist nach Spezifikation nicht garantiert) J. Henke (HAW) Threads 10. Juni 2011 9 / 18 Grundlegende Steuerung Die Klasse java.lang.Thread bietet eine Reihe von Methoden an, um das Verhalten des (aktuellen) Threads zu beinflussen: Die statischen Methoden beinflussen den aktuellen Thread, welcher den Code aktuell ausführt, dazu zählen unter anderem: I I I Thread.currentThread() liefert die Referenz auf der aktuellen Thread. Thread.yield() gibt den Rest der aktuell zugeteilten Rechenzeit ab. (Verhalten ist nach Spezifikation nicht garantiert) Thread.sleep(long)/Thread.sleep(long, int) legt den aktuellen Thread für die angegebene Dauer schlafen. J. Henke (HAW) Threads 10. Juni 2011 9 / 18 Grundlegende Steuerung Die Klasse java.lang.Thread bietet eine Reihe von Methoden an, um das Verhalten des (aktuellen) Threads zu beinflussen: Die statischen Methoden beinflussen den aktuellen Thread, welcher den Code aktuell ausführt, dazu zählen unter anderem: I I I Thread.currentThread() liefert die Referenz auf der aktuellen Thread. Thread.yield() gibt den Rest der aktuell zugeteilten Rechenzeit ab. (Verhalten ist nach Spezifikation nicht garantiert) Thread.sleep(long)/Thread.sleep(long, int) legt den aktuellen Thread für die angegebene Dauer schlafen. F Wenn der Thread vor dem Ablauf dieser Zeit per interrupt() geweckt wurde, wird eine (checked) InterruptedException ausgelöst. J. Henke (HAW) Threads 10. Juni 2011 9 / 18 Grundlegende Steuerung - Teil 2 Die nicht-statischen Methoden beeinflussen den Thread, auf dessen Referenz sie aufgerufen werden, dazu zählen unter anderem: J. Henke (HAW) Threads 10. Juni 2011 10 / 18 Grundlegende Steuerung - Teil 2 Die nicht-statischen Methoden beeinflussen den Thread, auf dessen Referenz sie aufgerufen werden, dazu zählen unter anderem: I interrupt() weckt aktuell schlafende Threads. J. Henke (HAW) Threads 10. Juni 2011 10 / 18 Grundlegende Steuerung - Teil 2 Die nicht-statischen Methoden beeinflussen den Thread, auf dessen Referenz sie aufgerufen werden, dazu zählen unter anderem: I I interrupt() weckt aktuell schlafende Threads. join() der aktuell laufende Thread wartet, bis der referenzierte Thread abgearbeitet ist. J. Henke (HAW) Threads 10. Juni 2011 10 / 18 Grundlegende Steuerung - Teil 2 Die nicht-statischen Methoden beeinflussen den Thread, auf dessen Referenz sie aufgerufen werden, dazu zählen unter anderem: I I I interrupt() weckt aktuell schlafende Threads. join() der aktuell laufende Thread wartet, bis der referenzierte Thread abgearbeitet ist. Getter und Setter für verschiedene Eigenschaften. J. Henke (HAW) Threads 10. Juni 2011 10 / 18 Grundlegende Steuerung - Teil 2 Die nicht-statischen Methoden beeinflussen den Thread, auf dessen Referenz sie aufgerufen werden, dazu zählen unter anderem: I I I I interrupt() weckt aktuell schlafende Threads. join() der aktuell laufende Thread wartet, bis der referenzierte Thread abgearbeitet ist. Getter und Setter für verschiedene Eigenschaften. stop() (deprecated !) bricht diesen Thread abrupt ab, kann daher zu inkonsitenen Verhalten führen und ist daher zu vermeiden. J. Henke (HAW) Threads 10. Juni 2011 10 / 18 Beenden der JVM bei Benutzung von Threads Die JVM (und damit das Programm) beendet sich nur wenn alle1 Threads beendet sind! 1 (nicht-dämon) J. Henke (HAW) Threads 10. Juni 2011 11 / 18 Beenden der JVM bei Benutzung von Threads Die JVM (und damit das Programm) beendet sich nur wenn alle1 Threads beendet sind! Hat man einen oder mehrere Threads, welche in einer Endlosschleife auf neue Arbeit warten, so muss man zu Beenden des Programms eine der folgenden Möglichkeiten implementieren: 1 (nicht-dämon) J. Henke (HAW) Threads 10. Juni 2011 11 / 18 Beenden der JVM bei Benutzung von Threads Die JVM (und damit das Programm) beendet sich nur wenn alle1 Threads beendet sind! Hat man einen oder mehrere Threads, welche in einer Endlosschleife auf neue Arbeit warten, so muss man zu Beenden des Programms eine der folgenden Möglichkeiten implementieren: Jeden Thread einzeln beenden (z.B. über interrupt()) 1 (nicht-dämon) J. Henke (HAW) Threads 10. Juni 2011 11 / 18 Beenden der JVM bei Benutzung von Threads Die JVM (und damit das Programm) beendet sich nur wenn alle1 Threads beendet sind! Hat man einen oder mehrere Threads, welche in einer Endlosschleife auf neue Arbeit warten, so muss man zu Beenden des Programms eine der folgenden Möglichkeiten implementieren: Jeden Thread einzeln beenden (z.B. über interrupt()) Über System.exit(int) die JVM hart beenden. 1 (nicht-dämon) J. Henke (HAW) Threads 10. Juni 2011 11 / 18 Beenden der JVM bei Benutzung von Threads Die JVM (und damit das Programm) beendet sich nur wenn alle1 Threads beendet sind! Hat man einen oder mehrere Threads, welche in einer Endlosschleife auf neue Arbeit warten, so muss man zu Beenden des Programms eine der folgenden Möglichkeiten implementieren: Jeden Thread einzeln beenden (z.B. über interrupt()) Über System.exit(int) die JVM hart beenden. Diese Threads vor dem starten als Dämonen kennzeichnen (setDemon(true)), ein Dämonthread hindert die JVM nicht daran sich selbst zu beenden. 1 (nicht-dämon) J. Henke (HAW) Threads 10. Juni 2011 11 / 18 Gliederung 1 Grundlagen Wiederholung: Threadgrundlagen Einfache Threads in Java 2 Fortgeschrittene Konzepte Executor Synchronisation J. Henke (HAW) Threads 10. Juni 2011 12 / 18 Der Executor Threads lassen sich nur einmal und nur mit einem einzigen Runnable starten. Auch lässt sich der Startzeitpunkt nicht wählen. J. Henke (HAW) Threads 10. Juni 2011 13 / 18 Der Executor Threads lassen sich nur einmal und nur mit einem einzigen Runnable starten. Auch lässt sich der Startzeitpunkt nicht wählen. Seit Java 1.5 gibt es eine Lösung, welche dies Einschränkungen beseitigt: Das Interface java.util.concurrent.Executer bzw. java.util.concurrent.ExecuterService. J. Henke (HAW) Threads 10. Juni 2011 13 / 18 Der Executor Threads lassen sich nur einmal und nur mit einem einzigen Runnable starten. Auch lässt sich der Startzeitpunkt nicht wählen. Seit Java 1.5 gibt es eine Lösung, welche dies Einschränkungen beseitigt: Das Interface java.util.concurrent.Executer bzw. java.util.concurrent.ExecuterService. Mit execute(Runnable) kann in implementierenden Klassen ein Runnable zur Bearbeitung eingereiht werden. J. Henke (HAW) Threads 10. Juni 2011 13 / 18 Der Executor Threads lassen sich nur einmal und nur mit einem einzigen Runnable starten. Auch lässt sich der Startzeitpunkt nicht wählen. Seit Java 1.5 gibt es eine Lösung, welche dies Einschränkungen beseitigt: Das Interface java.util.concurrent.Executer bzw. java.util.concurrent.ExecuterService. Mit execute(Runnable) kann in implementierenden Klassen ein Runnable zur Bearbeitung eingereiht werden. Details hängen von der konkreten Implementierung ab. J. Henke (HAW) Threads 10. Juni 2011 13 / 18 Der Executor Threads lassen sich nur einmal und nur mit einem einzigen Runnable starten. Auch lässt sich der Startzeitpunkt nicht wählen. Seit Java 1.5 gibt es eine Lösung, welche dies Einschränkungen beseitigt: Das Interface java.util.concurrent.Executer bzw. java.util.concurrent.ExecuterService. Mit execute(Runnable) kann in implementierenden Klassen ein Runnable zur Bearbeitung eingereiht werden. Details hängen von der konkreten Implementierung ab. java.util.concurrent.Executors bietet Fabrikmethoden für verschiedene Implementierungen J. Henke (HAW) Threads 10. Juni 2011 13 / 18 Gliederung 1 Grundlagen Wiederholung: Threadgrundlagen Einfache Threads in Java 2 Fortgeschrittene Konzepte Executor Synchronisation J. Henke (HAW) Threads 10. Juni 2011 14 / 18 Warum synchronisieren Vielfach müssen Threads Daten mit dem übrigen Programm austauschen. Das Laufzeitverhalten von Threads ist aber nicht berechenbar, d.h. nach jeder verarbeiteten Maschienoperation kann ein Thread unterbrochen werden. J. Henke (HAW) Threads 10. Juni 2011 15 / 18 Warum synchronisieren Vielfach müssen Threads Daten mit dem übrigen Programm austauschen. Das Laufzeitverhalten von Threads ist aber nicht berechenbar, d.h. nach jeder verarbeiteten Maschienoperation kann ein Thread unterbrochen werden. Da Schreibeoperationen in der Regel aus mehrern Maschienoperationen bestehen, müssen diese besonders geschützt werden, um inkonsistente (d.h. nur teilweise geschriebene) Daten zu vermeiden. J. Henke (HAW) Threads 10. Juni 2011 15 / 18 Das Schlüsselwort ’synchronized’ Eine einfache Methode Synchronisation in Java zu realisieren, ist das Schlüsselwort synchronized in der Definition einer Methode. J. Henke (HAW) Threads 10. Juni 2011 16 / 18 Das Schlüsselwort ’synchronized’ Eine einfache Methode Synchronisation in Java zu realisieren, ist das Schlüsselwort synchronized in der Definition einer Methode. Jedoch ist Vorsicht geboten, dies kann bei langen Methoden den Vorteil der Nebenläufigkeit zunichte machen. I In dem Fall Nutzung anderer Möglichkeiten -> Literatur J. Henke (HAW) Threads 10. Juni 2011 16 / 18 Das Schlüsselwort ’synchronized’ Eine einfache Methode Synchronisation in Java zu realisieren, ist das Schlüsselwort synchronized in der Definition einer Methode. Jedoch ist Vorsicht geboten, dies kann bei langen Methoden den Vorteil der Nebenläufigkeit zunichte machen. I In dem Fall Nutzung anderer Möglichkeiten -> Literatur synchronized sorgt dafür, dass zu jeder Zeit maximal ein Thread mit der Abarbeit eines Codesegments beschäftigt ist. J. Henke (HAW) Threads 10. Juni 2011 16 / 18 1 2 3 4 Das Schlüsselwort ’synchronized’ Eine einfache Methode Synchronisation in Java zu realisieren, ist das Schlüsselwort synchronized in der Definition einer Methode. Jedoch ist Vorsicht geboten, dies kann bei langen Methoden den Vorteil der Nebenläufigkeit zunichte machen. I In dem Fall Nutzung anderer Möglichkeiten -> Literatur synchronized sorgt dafür, dass zu jeder Zeit maximal ein Thread mit der Abarbeit eines Codesegments beschäftigt ist. Beispiel p u b l i c s y n c h r o n i z e d v o i d someMethod ( ) { // h i e r h ä l t s i c h m a x i m a l e i n T h r e a d } J. Henke (HAW) gleichzeitig Threads auf 10. Juni 2011 16 / 18 Collections API und Threads Bis auf Vector sind alle Collections nicht threadsicher! J. Henke (HAW) Threads 10. Juni 2011 17 / 18 Collections API und Threads Bis auf Vector sind alle Collections nicht threadsicher! Die Utilityklasse Collections biete jedoch Methoden, um auf eine bestehende Collection eine Synchronisierte Sicht zu erhalten. Anschließend müssen alle Zugriffe über diese Sicht auf die Collection abgewickelt werden. J. Henke (HAW) Threads 10. Juni 2011 17 / 18 1 Collections API und Threads Bis auf Vector sind alle Collections nicht threadsicher! Die Utilityklasse Collections biete jedoch Methoden, um auf eine bestehende Collection eine Synchronisierte Sicht zu erhalten. Anschließend müssen alle Zugriffe über diese Sicht auf die Collection abgewickelt werden. Beispiel L i s t <S t r i n g > m y L i s t = C o l l e c t i o n s . s y n c h r o n i z e d L i s t ( new L i n k e d L i s t <S t r i n g >() ) ; J. Henke (HAW) Threads 10. Juni 2011 17 / 18 Ende Vielen Dank für die Aufmerksamkeit. Sind noch Fragen offen? J. Henke (HAW) Threads 10. Juni 2011 18 / 18