1. Example 01: HipHop

1.1. Aufgabenstellung

Erstellen Sie ein Programm mit zwei Threads, das die beiden Wörter "Hip" und "HOP" in einer Endlosschleife unterschiedlich schnell ausgibt.

Realisieren Sie zwei Programmvarianten:

  1. Ableitung von der Klasse Thread

  2. Implementierung des Interfaces Runnable.

1.2. Bildschirmausgabe

Hip HOP Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip Hip Hip Hip Hip HOP Hip

Lösung: HipHop2

2. Example 02: Thread-Name und -Priorität

2.1. Aufgabenstellung

Schreiben Sie ein Programm, das den Namen und die Priorität des Threads ausgibt, der die Methode main ausführt.

2.2. Bildschirmausgabe

Name: main
Prioritaet: 5

3. Example 03: start/stop eines Threads

3.1. Aufgabenstellung

Entwickeln Sie eine Klasse, die das Interface Runnable implementiert sowie die Methoden

  • main,

  • start und

  • stop.

start erzeugt einen neuen Thread und startet ihn, stop beendet ihn.

Für jeden neu erzeugten Thread ist auch ein neuer Name zur Unterscheidung zu wählen. Der Thread soll seinen Namen in Abständen von zwei Sekunden ausgeben.

In main können die Methoden start und stop, gesteuert über Tastatureingabe, aufgerufen werden.

Verwenden Sie zur Tastatureingabe System.in.read()

3.2. Bildschirmausgabe

s
Thread Nr. 1
Thread Nr. 1
Thread Nr. 1
p
s
Thread Nr. 2
Thread Nr. 2
Thread Nr. 2
Thread Nr. 2
p
s
Thread Nr. 3
Thread Nr. 3
p
e

Process finished with exit code 0

4. Example 04: Logger

4.1. Aufgabenstellung

Zwei parallel laufende Threads sollen Nachrichten in dieselbe Protokolldatei schreiben.

Entwickeln Sie die Klasse LogFile, die die Protokolldatei verwaltet. Die Klasse soll die Methode public synchronized void writeLine(String msg) enthalten, die eine Zeile bestehend aus Systemzeit und msg schreibt.

Erstellen Sie ein Testprogramm, das die Protokolldatei erzeugt, zwei Threads startet, die in diese Datei mehrere Nachrichten schreiben, und das die Datei schließt, nachdem die Ausführung der beiden Threads beendet ist.

Verwenden sie die Klasse DateTimeFormatter

4.2. Bildschirmausgabe

Thread Thread-0 gestartet
Thread Thread-1 gestartet
Warte auf Beendigung beider Threads ...
Ende

Process finished with exit code 0

4.3. Datei

01.04.2020 21:59:18	Thread-0
01.04.2020 21:59:18	Thread-0
01.04.2020 21:59:18	Thread-0
01.04.2020 21:59:18	Thread-1
01.04.2020 21:59:18	Thread-1
01.04.2020 21:59:18	Thread-1
01.04.2020 21:59:18	Thread-1
01.04.2020 21:59:18	Thread-1
01.04.2020 21:59:18	Thread-1
01.04.2020 21:59:18	Thread-0
01.04.2020 21:59:18	Thread-1
01.04.2020 21:59:18	Thread-1
01.04.2020 21:59:18	Thread-1
01.04.2020 21:59:18	Thread-1
...

5. Example 05: Bankkonto

5.1. Aufgabenstellung

Schreiben Sie ein Programm, in dem mehrere Threads zur gleichen Zeit einen zufälligen Betrag auf dasselbe Konto einzahlen.

Die Additionsmethode soll aus den einzelnen Threads mehrfach aufgerufen werden.

Vergleichen Sie am Ende die überwiesenen Beträge der einzelnen Threads mit dem Gesamtsaldo am Konto. Stimmen beide Beträge nicht überein, haben Sie eine Race Condition.

Schreiben Sie das Programm so, dass keine Additionen verloren gehen.

5.2. Hinweise zur Implementierung

5.2.1. Überblick

Das Programm besteht aus drei Klassen:

  • Konto: Die ist die geteilte Ressource

  • Manager: Der jeweilige Task. Zählt die Anzahl der Transaktionen sowie die Betragssumme.

  • Test: Startet die Threads mit ihren Tasks (Manager), wartet 10 sek., unterbricht alle Threads und sammelt schließlich die Ergebnisse ein (Anzahl Transaktionen und gebuchter Betrag).

5.2.2. Klasse Konto

bsp05 konto

Pseudo-Code für Methode add(…​):

  1. Der saldo wird in eine lokale Variable eingelesen.

  2. Die Verarbeitung dauert 10 ms (→ Thread.sleep(10))

  3. Der Betrag value wird zum saldo addiert.

5.2.3. Klasse Manager

bsp05 manager

Pseudo-Code für Methode run(…​):

  1. Ermittle per Zufall einen Wert (value) zwischen 1 und 10;

  2. konto.add(value)

  3. Inkrementiere 'transaktionen'

  4. Summiere den value zu summe

  5. Warte 2 Millisekunden

5.2.4. Klasse Test

bsp05 test

Pseudo-Code für Methode main(…​):

  1. Erstelle ein Konto für sämtliche Threads

  2. Erstelle eine Map und speichere als key den Thread und als Value den Manager

  3. Erstelle Threads und Manager in der gewünschten Anzahl (ANZAHL_THREADS) und starte diese.

  4. Warte die gewünschte Zeit (SEKUNDEN)

  5. Unterbreche alle Threads (interrupt)

  6. Warte bis alle Threads fertig sind und

  7. sammle die Ergebnisse ein (Transktionen und Summe)

  8. Gib den Kontostand sowie die Gesamttransaktionen und Gesamtsummen der Threads auf der Console aus.

Wird ein Thread während des sleep unterbrochen, ist in der catch-Klausel wieder ein interrupt aufzurufen

try {
  Thread.sleep(10);
} catch (InterruptedException e) {
  ...
  Thread.currentThread().interrupt();
}

5.3. Bildschirmausgabe

main: Warte 10 Sekunden ...
Gesamtanzahl Transaktionen: 969
Gesamtsumme: 5269
Saldo: 5269

Process finished with exit code 0

5.4. Erweiterung

Ergänzen Sie die Klassen Konto und Manager mit einem Java-Logger. Jedesmal, wenn ein Thread im sleep unterbrochen wird (interrupt), ist eine Meldung auszugeben:

Apr 10, 2020 10:31:42 AM at.htl.multithreading.exercise.ex05.Konto add
SEVERE: Thread-6: Konto.add() interrupted

Verwenden Sie hierzu den java.util.Logger:

private static final Logger LOG = Logger.getLogger(Konto.class.getSimpleName());

Dieser Logger soll ausschließlich in eine Datei "KontoLogger.txt" schreiben:

Handler fileHandler = new FileHandler("KontoLogger.txt");
LOG.addHandler(fileHandler);

Schalten Sie hierzu den ConsoleHandler aus:

LOG.setUseParentHandlers(false);

Das vorgegebene Ausgabeformat erhalten sie durch Verwendung eines SimpleLoggers:

fileHandler.setFormatter(new SimpleFormatter());
Apr 10, 2020 10:31:42 AM at.htl.multithreading.exercise.ex05.Konto add
SEVERE: Thread-6: Konto.add() interrupted