Nebenläufige Programmierung mit Threads

Anlegen von Threads

Threads erzeugen *

Implementiere ein Thread-Beispiel und erzeuge in main() 100 Threads. Die run()-Methode soll dabei lediglich die laufende Threadnummer anzeigen. Wir erhalten dann auf dem Bildschirm Meldungen der Art

1 
2
1
2
3
2

Wie viele Threads lassen sich erzeugen, bis das System "steht"? Beobachte den Speicherverbrauch unter dem Task-Manager (Alt/Ctrl/Del) an. Lässt sich abschätzen, was ein Thread "kostet"?

Lösung

Thread-Eigenschaften

Threads schlafen *

Das unter Unix bekannte Programm sleep kann man auf der Kommandozeile aufrufen und es schläft dann eine Zeit lang.

  1. Implementiere das Programm in Java, sodass man auf der Kommandozeile schreiben kann:
     $ java Sleep 22
    Dann soll das Programm 22 Sekunden schlafen.
  2. Jetzt sollen nicht nur Sekunden verwendet werden. Erweitere das Programm, sodass ein zweites Argument auch Minuten, Stunden oder Tage wartet. Wirf für die Schreibweise einen Blick in das C-Programm.

Lösung

Dämonen *

Implementiere einen java.lang.Thread in einer Endlosschleife. Er soll jede Sekunde eine Meldung wie etwa "Hallo" auf dem Bildschirm ausgeben. Markiere den Thread einmal als Dämon und einmal nicht.

Lösung

Threads beobachten Dateien **

Schreibe eine Klasse DateiBeobachter mit einem Konstruktor DateiBeobachter(String) und DateiBeobachter(java.io.File). Die Klasse soll beobachten, ob sich eine Datei im Dateisystem ändert.

Lösung

Threads unterbrechen *

Man kann einen Thread mit der stop()-Methode unterbrechen, doch so gibt man ihm keine Chance, sich ordentlich zu beenden. Daher kann man einen Interrupt senden, der ein Flag setzt, der in der run()-Methode abgefragt werden kann. Schreibe ein Programm, welches sich in einer Endlosschleife befindet. Reagiere auf einen Abbruch von außen. Lese aus java.lang.Thread die Beschreibung zu den Methoden isInterrupted() und interrupt().

Threads mit Namen ansprechen *

Schreibe eine eigene Klasse ThreadCollection mit einer Funktion createThread( String name, Runnable run), die einen Thread run startet und in einen Assoziativspeicher legt. Schreibe zusätzlich eine Methode stopThread( String name), die den Thread beendet.
Mit dieser Klasse ist es einfach möglich, Thread mit Namen anzusprechen. Man benötigt dann keine Referenz mehr.

Ein Timer-Label **

Klasse Uhrzeit, der Frame
Klasse TimeLabel

Exceptions auffangen (25 Minuten)

Implementiere einen Thread, der durch die Division mit Null eine Exception wirft. Fange den Fehlerfall dieses speziellen Threads durch einen UncaughtExceptionHandler ab.

Lösung

Executor

 Thread-Pool (20 Minuten)

Erzeuge mit ExecutorService s = Executors.newCachedThreadPool(); einen java.util.concurrent.ExecutorService und führe mit s.execute() Programmcode vom folgenden Kern in run() aus java.lang.Runnable aus:

class MyRunnable implements Runnable
{
public void run()
{
System.out.println( Thread.currentThread() );
// try {
// Thread.sleep( 1000 );
// } catch ( InterruptedException e ) {
// e.printStackTrace();
// }
}
}

Das Programm sieht dann so aus:

ExecutorService s = Executors.newCachedThreadPool();
Runnable run = new MyRunnable();
s.execute( run );
s.execute( run );
s.execute( run );
s.execute( run );
s.execute( run );
s.execute( run );
...

Welchen Unterschied macht es, ob man die Zeilen auskommentiert oder wieder in den Programmfluss integriert?

Synchronisation

Motivation für Synchronisierung *

Es gibt die Objektvariable Point p = new Point() und gleichzeitig zwei Threads. Der eine führt p.setLocation(1, 2) aus, der andere p.setLocation(2, 1). Welches Problem könnte durch die Threads entstehen, wenn sie parallel auf die Methoden zugreifen?

Löse das Problem durch die Möglichkeiten der Java-API.