Threads
Motivation
- langwierige Operationen
- warten auf IO
- modellieren paralleler Abläufe
Warten auf IO
- Szenario
- Mehrere Clients connecten zu einem Server, um Daten zu empfangen. Ohne Concurrency könnte sich gleichzeitig nur ein einziger Client verbinden.
- Lösung
- Jedem Client wird ein Thread zugeteilt, welcher sich um die Kommunikation kümmert.
Einbettung im OS
- moderne Prozessoren verfügen über mehrere CPUs/Cores
- ein Prozess kann Threads erzeugen
- der OS-Scheduler verwaltet, welcher Prozess bzw. Thread wann arbeiten darf
- ein Thread kann jederzeit vom OS pausiert werden ⚠️
Time Slicing
Threads > Prozessoren
Hyperthreading
Erzeugung
Thread thread = new Thread();
thread.start();Festlegung des auszuführenden Codes
ThreadextendenRunnableimplementieren
Thread extenden
public class MyThread extends Thread {
@Override
public void run(){
System.out.println("MyThread running");
}
}MyThread myThread = new MyThread();
myThread.start();
Runnable implementieren
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("MyRunnable running");
}
}Runnable runnable = new MyRunnable();
new Thread(runnable).start();
runnable = () -> foo();
new Thread(runnable, "name").start();
👍
- Interfaces sind dazu da, Verhalten zu deklarieren
- Möglichkeit, andere Klassen zu extenden
Beispiel
public class ThreadExample {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());
for (int i = 0; i < 4; i++) {
new Thread("" + i) {
@Override
public void run() {
System.out.println("Thread: " + getName() + " running");
}
}.start();
}
}
}main
Thread: 1 running
Thread: 2 running
Thread: 0 running
Thread: 3 running
Fehler
Runnable runnable = () -> foo();
new Thread(runnable).run();
new Thread(runnable).start();
run läuft im Mainthread
Meta
Interfaces trennen das was vom wie
Threads trennen das was vom wann
Kontrolle
Thread thread = Thread.currentThread();
Liefert den aktuellen Thread
Thread.sleep(1000); //1000ms
Pausiert den aktuellen Thread
Zum Stoppen muss run enden
InterruptedException
Thread.currentThread().interrupt();- wird von vielen
Thread-Methoden geworfen - unterbricht einen laufenden Thread
- im unterbrochenen Thread wird eine
InterruptedExceptionausgelöst
catch definiert
join
Thread thread = new Thread(() -> {
sleep(1000);
System.out.println("guaranteed");
});
thread.start();
thread.join();
System.out.println("order");Wenn Thread A während seiner Ausführung B.join aufruft, dann wartet A mit seiner weiteren Ausführung, bis B dead ist.
Daemon Threads
thread.setDaemon(true);- in UNIX ein Hintergrundprozess, in Windows genannt Service
- wenn nur mehr Daemon Threads laufen, beendet sich die JVM ⟹ Hintergrundaufgaben
- muss vor dem Starten gesetzt sein
Synchronisation
public class IdGenerator {
int lastUsedId;
public int incrementValue() {
return ++lastUsedId;
}
}- ein Thread ✔️
- zwei Threads mit demselben
IdGenerator:- A kriegt 1, B kriegt 2,
lastUsedIdist 2 - A kriegt 2, B kriegt 1,
lastUsedIdist 2 - A kriegt 1, B kriegt 1,
lastUsedIdist 1 ❌
- A kriegt 1, B kriegt 2,
Der dritte Fall ist selten (1:20000), aber er passiert
Atomare Operationen
- ganz oder gar nicht
- auf Datenbanken Transaktion
- in Java:
- Variablen lesen (außer
long/double) - Variable schreiben (außer
long/double)
- im Package
java.util.concurrent.atomicfinden sich Klassen wieAtomicIntegermit hilfreichen Methoden
synchronized Methoden
public synchronized int incrementValue() {
return ++lastUsedId;
}- erzeugt einen Mutex (MUTual EXclusion)
- nur ein Thread kann diesen Block gleichzeitig betreten
synchronized Blöcke
public void foo() {
// code
synchronized(object) {
// code
}
}- nur ein Thread kann pro Objekt das Lock / den Monitor halten
- bevor ein Thread den Block betreten darf, muss er das Lock requesten
- bekommt er das Lock, fährt der Thread fort
- ansonsten blockt der Thread und wartet
- ein Thread kann dasselbe Lock mehrmals halten
Locking

Methoden Locks
eine synchronized Methode locked
thisXXX.classbei statischen Methoden- 👍 Alternative: gut benanntes Lock-Objekt
Lifecycle

Busy waiting
public class MySignal {
private boolean hasDataToProcess = false;
public synchronized boolean hasDataToProcess() {
return this.hasDataToProcess;
}Thread A übergibt Daten, Thread B wartet:
private MySignal sharedSignal;
while(!sharedSignal.hasDataToProcess()){
// do nothing... busy waiting
}
sharedSignal.processData();
wait/notify
synchronized(elevator) {
while(burning)
elevator.wait();
}
synchronized(elevator) {
extinguishFire();
elevator.notifyAll();
}
wait
elevator.wait();Object-Methode- muss in
synchronized-Block gecalled werden, sonstIllegalMonitorStateException💥 - Thread geht in den Zustand blocked
- Thread gibt alle Locks frei
- immer in einem
while- mehrere Threads callen
wait - Spurious Wakeups 👻
- mehrere Threads callen
notify/notifyAll
elevator.notify();Object-Methode- muss in
synchronized-Block gecalled werden, sonstIllegalMonitorStateException💥 - holt einen/alle Threads aus dem Zustand waiting, diese müssen nun wieder das Lock requesten
- gehaltene Locks werden nicht freigegeben
private boolean hasDataToProcess = false;
private MonitorObject monitor = new MonitorObject();
public void setData(Object data) throws InterruptedException {
synchronized (monitor) {
while (hasDataToProcess)
monitor.wait();
hasDataToProcess = true;
monitor.notifyAll();
}
}
public void processData() throws InterruptedException {
synchronized (monitor) {
while (!hasDataToProcess)
monitor.wait();
doStuff(dataToProcess);
hasDataToProcess = false;
monitor.notifyAll();
}
}
Deadlock
- Website connected zu zwei Datenbanken
- n mögliche Connections je Db
- Operation A verbindet sich zu Db1, dann Db2
- Operation B verbindet sich zu Db2, dann Db1
- n User führen A aus
- n User führen B aus
- alle A-User warten darauf, dass ein B-User seine Connection hergibt
- die warten allerdings alle auf eine Connection der A-User
weitere Probleme
- Starvation
- Thread bekommt nie alle Resourcen, um seine Arbeit zu beenden
- Livelock
- wie eine Deadlock, aber Threads sind busy waiting
Best practice
- so wenig Abhängigkeiten wie möglich
- so wenig
synchronizedwie möglich - testen, testen, testen
- Serverseitig synchronisieren (kapseln)