Thread Funktionalität als Sprachkonstrukte oder externe Bibliotheken
Java-Implementierung von Threads, enthalten in dem Java-Package java.lang:
Erzeugung von Threads:
ein Objekt einer geeigneten Klasse erzeugen,
Aufruf einer Methode dieses Objekts.
Für die Klasse gibt es zwei Möglichkeiten:
Subklasse von Thread
Implementierung des Runnable-Interface
Der Thread-Konstruktor und die Thread-Methoden start() und join() haben die folgenden Spezifikationen.
public Thread(Runnable target) public Thread(Runnable target, String name) public Thread(ThreadGroup group, Runnable target, String name) public synchronized void start() public final void join() throws InterruptedException
erster Eindruck eines parallelen Java-Programms:
class Action implements Runnable {
int var;
public Action(int v) { var = v; }
public void run() { doSomeWork(var); }
}
Thread t1 = new Thread(new Action(1));
Thread t2 = new Thread(new Action(2));
Thread t3 = new Thread(new Action(3));
try {
t1.start(); t2.start(); t3.start();
t1.join(); t2.join(); t3.join();
}
catch (InterruptedException e) { ... }
In verschiedenen run()-Methoden u.U. gleichzeitiger Zugriff auf globale Variablen.
Wir können nicht verhindern, daß Schreib- oder Lese-Operationen auf den globalen Speicher in nebenläufigen Prozessen stattfinden und sichtbar werden.
Das Java-Sprachkonstrukt synchronized hat die folgenden Varianten.
synchronized (object) { ... }
synchronized (static object) { ... }
synchronized type methodName(...) { ... }
static synchronized type methodName(...) { ... }
{...} ausführen kann
Die Semantik von
synchronized type methodName(...) { S1; ...; Sn; }
entspricht
type methodName(...) {
synchronized(this) { S1; ...; Sn; }
}
Bemerkungen:
Problem: Initialisierung innerhalb eines parallelen Ablaufs.
Beispiel: Summe von Vektoren.
Zur Verfügung stehen uns die Object-Funktionen wait() und notify() mit den folgenden Spezifikationen:
public final void wait() throws InterruptedException
public final void wait(long timeout)
throws InterruptedException
public final void notify()
public final void notifyAll()
wait() nur innerhalb eines synchronized Abschnitts
Fall eines beliebigen Booleschen Ausdrucks der erfüllt sein soll.
Es gibt zwei Operationen `V' (Abkürzung für holländisch `frei') und `P' (für `passieren') auf Semaphoren `sem':
Implementierungsskizze:
sem.P(): synchronized (mux) {
while (s <= 0) { "waiting = true"
wait(); }
s--;
}
sem.V(): synchronized (mux) {
s++;
if ("some are waiting") { notify(); }
}
Implementierungen: Sema.java, Semaphore.java
Mit Barrieren kann man warten, bis sich eine vorgegebene Anzahl von Teilnehmern angemeldet hat, und dann weiterarbeiten.
public class Barrier {
private int n, b;
public Barrier(int i) {
n = i; b = 0;
}
public synchronized void check() {
b++;
if (b < n) {
try { this.wait();
} catch (InterruptedException e) {}
}
else { b = 0;
this.notifyAll();
}
}
}
public class Barrier {
private int n, b;
private Sema bs, bl;
public Barrier(int i) {
n = i; b = 0;
bs = new Sema(0);
bl = new Sema(1);
}
public void check() {
bl.P();
b++;
if (b < n) {
bl.V(); bs.P();
}
else {
b = 0;
for (int j=1; j<n; j++) { bs.V(); }
bl.V();
}
}
}
n Produzenten erzeugen Daten, die an m Konsumenten weitergegeben werden sollen. Zur Weitergabe der Daten dient ein Puffer, der in der Lage sein soll, k Daten zu speichern ( 1 <= n, 1 <= m, 1 <= k ). Falls der Puffer voll ist, sollen die Produzenten warten, bis wieder Platz ist, und falls der Puffer leer ist, sollen die Konsumenten warten, bis wieder Daten vorhanden sind. Falls keine Arbeit mehr anliegt, sollen die Produzenten und die Konsumenten terminieren.
Der Puffer wird als Ringpuffer implementiert, siehe Abbildung E1. Die Variablen `front' und `rear' zeigen jeweils auf den nächsten vollen Platz zum Lesen des Puffers bzw. auf den nächsten freien Platz zum Schreiben. Falls der Puffer nicht voll ist, kann ein Produzent in den Puffer schreiben, und falls der Puffer nicht leer ist, kann ein Konsument aus dem Puffer lesen.
Die Synchronisation muß somit sicherstellen, daß der Produzent
wartet, falls der Puffer voll ist, und der Konsument wartet,
falls der Puffer leer ist. Das heißt, sei x die Anzahl der
Elemente im Puffer, dann muß immer gelten
1 <= x <= k.
Insbesondere muß gelten
x <= k
damit der Produzent eine Nachricht schreiben darf.
Und es muß gelten
1 <= x
damit der Konsument eine Nachricht lesen kann.
Implementierung: BoundedBuffer.java
© Universität Mannheim, Rechenzentrum, 2000-2009.
Last modified: Wed Sep 12 21:28:54 CEST 2009