Skip to content
On this page
10. Multithreading
1

Threads

Objektorienteirte Programmierung 2

22.05.2023
10. Multithreading
2

Multithreading

  • Was passiert, wenn ein Methodenaufruf blockiert?
  • Beispiele
    • Netzwerkzugriff
    • Filesystemzugriff
    • Datenverarbeitung
    • Warten auf User Input
22.05.2023
10. Multithreading
3

Audio

java
AudioRecorder recorder = new AudioRecorder();

double[] samples = new double[1000];

recorder.setup(8000);

for (int i = 0; i < 100; i++) {
    // dauert für 1000 samples 1/8 [s] = 0.125[s]
    int len = recorder.readSamples(samples, samples.length);
    System.out.printf("samples gelesen: %d\n", len);
}
22.05.2023
10. Multithreading
4

Blocking Call

Ein Blocking Call ist der Aufruf einer Methode, welche den Programmfluss unterbricht. Dabei wird oft unterschieden zwischen:

  • rechenintensiven Methoden (z.B. Busy Loop)
  • I/O und "schlafenden" Methoden (z.B. sleep, wait, ...)
22.05.2023
10. Multithreading
5

Einen Thread schlafen legen

java
// Zeit in [ms] als Argument
Thread.sleep(1000);
22.05.2023
10. Multithreading
6

Threads

Ein Thread ist ein Konstrukt, welches vom Betriebssystem (Scheduler) unterstütz werden muss. Ein Thread dient zur quasi-parallellen Abarbeitung von Aufgaben. Multithreading erlaubt es mehrere Threads quasi-parallel laufen zu lassen.

22.05.2023
10. Multithreading
7

Runnable

  • In Java nimmt ein Thread ein Objekt, welches Runnable implementiert entgegen (hat nur eine einzige Methode void run().
  • Ein Thread kann genau einmal gestartet werden (start), worauf run des Runnable aufgerufen wird.
22.05.2023
10. Multithreading
8

Thread instanzieren und starten

java

Runnable runnable = new Runnable() {
    
    @Override
    public void run() {
        System.out.println("hello");
        System.out.println("done");
    }
};

Thread thread = new Thread(runnable, "Simple Thread");
thread.start();
22.05.2023
10. Multithreading
9

Mehrere Threads gleichzeitig starten

  • Moderne Betriebsysteme erlauben das Ausführen mehrerer Threads quasi-gleichzeitig
  • Das OS verwendet einen Scheduler um allen Threads ein Time-Slice der CPU zur Verfügung zu stellen.
  • Wird ein Thread schlafen gelegt, so braucht er keine CPU-Zeit und wird erst wieder "geweckt" falls es notwendig ist.
22.05.2023
10. Multithreading
10

Thread schlafen legen

java
Runnable runnable = new Runnable() {
    
    @Override
    public void run() {
        System.out.println("Sleeping 1s");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("done");
    }
};

Thread thread = new Thread(runnable, "Simple Thread");
thread.start();
22.05.2023
10. Multithreading
11

Infinite Loops

  • Typische Anwendung eines Threads für parallelle Aufgaben
java
Runnable runnable = new Runnable() {

    @Override
    public void run() {

        while (true) {
            System.out.println("Sleeping 1s");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
};

Thread thread = new Thread(runnable, "Simple Thread");
thread.start();
22.05.2023
10. Multithreading
12

GUI Thread

User Interfaces arbeiten häufig mit einem UI Thread, welcher für das abarbeiten von InputEvents zuständig ist (MouseClick, KeyPress, repaint). Der UI Thread schläft in der Regel ständig und ist darauf ausgelegt, dass Methoden non-blocking sind.

Falls eine Methode blockiert, wird das GUI unresponsive.

Blockierende Calls müssen daher in Threas ausgelagert werden.

22.05.2023
10. Multithreading
13

Signalisieren

  • Threads können sich untereinander koordinieren.
    • aufeinander warten
    • Daten austauschen
    • sich gegenseitig wecken
  • Hierzu gibt es Sprachprimitiven von Object
    • wait()
    • notify()
22.05.2023
10. Multithreading
14

Die Gesetzte von Multithreading

Multithreading hilft bei blockierenden, sowie rechenintensiven Methodenaufrufen. Allerdings gelten beim Zugriff auf Objekte und Resourcen ganz neue Regeln, welche nicht offensichtlich sind.

Die main() Methode startet einen ersten Thread, welche "Main-Thread" genannt wird.

22.05.2023
10. Multithreading
15

Zugriff auf Objekte

  • Objektzugriffe müssen zwischen mehreren Threads immer "gelockt" geschehen.
  • ... nur einer der Threads darf gleichzeitig auf ein Objekt zugreifen.
  • synchronized erlaubt eine Mutual Exclusion (mutex) eines Codeblocks.
  • Wenn der Codeblock bereits belegt ist, wartet der Thread, bis dieser wieder freigegeben wird. Dies wird auch locking, oder ReentrantLock genannt.
22.05.2023
10. Multithreading
16

Ohne synchronized: Folgendes Beispiel ist unsauber, da der Zugriff auf a ohne synchronized von zwei Threads stattfindet.

java

public class Main {

	int a = 0;

	private void launch() throws InterruptedException {
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				a++;
				System.out.println("a is now: " + a);
			}
		});
		thread.start();
		a++;
		System.out.println("a is now: " + a);
		thread.join(); // warten bis Thread fertig ist
	}

	public static void main(String[] args) throws InterruptedException {
		Main main = new Main();
		main.launch();
	}

}
22.05.2023
10. Multithreading

Zugriff mit synchronized

17
java
public class Main {
	int a = 0;
	final Object lock = new Object();

	private void launch() throws InterruptedException {
		Thread thread = new Thread(new Runnable() {
			@Override
			public void run() {
				synchronized (lock) {
					a++;
					System.out.println("a is now: " + a);
				}

			}
		});
		thread.start();

		synchronized (lock) {
			a++;
			System.out.println("a is now: " + a);
		}

		thread.join(); // warten bis Thread fertig ist
	}

	public static void main(String[] args) throws InterruptedException {
		Main main = new Main();
		main.launch();
	}
}
22.05.2023
10. Multithreading
18

Auf Threads warten mit join

join() wartet so lange, bis ein Thread durchgelaufen ist.

22.05.2023
10. Multithreading
19

Einen Thread unterbrechen mit interrupt()

Ein Thread kann mit interrupt() unterbrochen werden, was zu einer InterruptedException führt. z.B, falls ein Thread am schlafen ist.

Ein Thread kann nicht gekillt werden.

Will man einen Thread an allen Stellen terminieren, so muss dieser auch an allen Stellen terminierbar implementiert sein. Dies kann z.B. durch das prüfen einer Variablen geschehen.

22.05.2023
10. Multithreading
20

Kritische Resourcen kopieren

  • Threads dürfen nicht mit den gleichen Resourcen gleichzeitig arbeiten (vgl. Locking).
  • Durch das Kopieren der Resourcen wird sichergestellt, dass beide Threads eigene Kopien der Resourcen haben.
  • Beispiel: AudioRecorder
22.05.2023
10. Multithreading
21

Weiterführende Konstrukte für Multithreading

  • ArrayBlockingQueue
  • AtomicInteger, AtomicBoolean, etc.
  • Executor, ThreadPool
22.05.2023