Threads - users.etech.haw

Werbung
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
Herunterladen