Document

Werbung
Universität Karlsruhe (TH)
Forschungsuniversität · gegründet 1825
Software Engineering für
moderne, parallele Plattformen
5. Parallelität in Java
Dr. Victor Pankratius
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Agenda
• Erzeugen von Fäden
• Konstrukte zum Schützen kritischer Abschnitte
• Konstrukte für Warten und Benachrichtigung
• Java.util.concurrent
• Kollektionen
• Asynchrone Ausführung / Thread Pools
• Synchronisierer
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
2
Konstrukte zum Erzeugen von Parallelität
• Seit Java 1.0: Eingebaute Klassen und Schnittstellen für
parallele Programmierung:
• Interface java.lang.Runnable
public interface Runnable {
public abstract void run();
}
• Klasse java.lang.Thread
public class
public
public
public
public
…
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Thread implements Runnable {
Thread(String name);
Thread(Runnable target)
void start();
void run();
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
3
Konstrukte zum Erzeugen von Parallelität
Faden erzeugen
Methode 1
Methode 2
Implementieren der
Schnittstelle Runnable
Anlegen einer Subklasse
von Thread
Implementieren der
Methode Run()
Überschreiben der
Methode run()
Übergabe einer Instanz
an einen Konstruktor eines
Thread-Objekts thread
Anlegen einer Instanz
thread der Subklasse
Aufruf der Methode
thread.start()
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
4
Konstrukte zum Erzeugen von Parallelität
Beispiel: Methode 1
• Klasse, die Runnable implementiert:
class ComputeRun implements Runnable {
long min, max;
ComputeRun(long min, long max) {
this.min = min; this.max = max;
}
public void run() {
// Parallele Aufgabe
}
}
• Erzeuge und starte Kontrollfaden:
• ComputeRun c = new ComputeRun(1,20);
new Thread(c).start();
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
• Starten des neuen
Kontrollfadens. Erst das
erzeugt die neue Aktivität!
• Die Methode start()
kehrt sofort zurück, der
neue Kontrollfaden arbeitet
nebenläufig weiter.
• Kein Neustart: start()
darf nur einmal aufgerufen
werden.
• run() nicht direkt aufrufen
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
5
Konstrukte zum Erzeugen von Parallelität
Beispiel: Methode 2
• Klasse, die von Thread erbt:
class ComputeThread extends Thread {
long min, max;
ComputeThread(long min, long max) {
this.min = min; this.max = max;
}
public void run() {
// Parallele Aufgabe
}
}
• Erzeuge und starte Kontrollfaden:
ComputeThread t = new ComputeThread(1,10);
t.start();
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
6
Lebenszyklus eines Fadens
Ein Faden kann in einem von sechs Zuständen sein
(abfragen mit getstate())
• NEW
• Faden wurde erstellt, aber start() noch nicht aufgerufen
• RUNNABLE
• Faden wird ausgeführt
• BLOCKED
• Faden wird nicht ausgeführt, weil er auf Ressource wartet (z.B. Sperre)
• WAITING
• Faden wird nicht ausgeführt, weil er Object.wait() oder Thread.join()
aufgerufen hat
• TIMED_WAITING
• Faden wird nicht ausgeführt, weil er Thread.sleep() bzw. Object.wait()
oder Thread.Join() mit einem Timeout-Wert aufgerufen hat
• TERMINATED
• Ausführung ist beendet. Methode run() wurde normal beendet oder durch
auslösen einer Ausnahme
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
7
Kritische Abschnitte
• Monitor-Konzept: Jedes Objekt kann Monitor sein
• Jedes Objekt hat implizit assoziierte Sperre
• Gesperrt wird automatisch mit Hilfe des
synchronized-Konstrukts
• Synchronized ist block-orientiert
/*synchronisierte Methode*/
synchronized void foo(){
// Rumpf ist kritischer
// Abschnitt
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Alternative:
...
/*synchronisierter block*/
synchronized (obj) {
// kritischer Abschnitt
}
...
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
8
Kritische Abschnitte
Sperrkonstrukte
• Ab Java 5: Zusätzliches Sperrkonstrukt ohne
Blockorientierung, das explizit gesperrt/entsperrt
werden kann: Lock in
java.concurrent.locks
//neu in Java 5
import java.util.concurrent.locks.*;
Lock lock = new ReentrantLock(); //funktioniert
auch bei
//Rekursion
…
lock.lock();
…
lock.unlock();
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
9
Kritische Abschnitte
Sperrkonstrukte
Beispiel für weiteres Sperrkonstrukt in java.util.concurrent.locks
• ReentrantReadWriteLock
• Nützlich für parallele Algorithmen, die Datenstruktur häufig lesen und
selten schreiben bzw. aktualisieren
• Besitzt ein Paar von getrennten Lock-Objekten für Lese- und
Schreibsperren (readLock,
readLock, writeLock
writeLock)
• Eine beliebige Anzahl von Fäden kann mit readLock() die Lesesperre
acquirieren, solange kein Faden die Schreibsperre acquiriert oder bereits
gesetzt hat
• Wenn Faden Schreibsperre setzen will, werden keine neuen
Lesesperren mehr elaubt. Nachdem alle Leser ihre Lesesperren
freigegeben haben, acquiriert der Schreiber die Schreibsperre. Es
werden keine Lesezugriffe mehr erlaubt, bis Schreiber fertig ist.
• Ein Schreiber kann Schreibsperre zu einer Lesesperre “umwandeln”,
indem er eine Lesesperre acquiriert und dann die Schreibsperre freigibt
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
10
Sperrkonstrukte
Performanzvergleich
• Doug Lea:
The java.util.concurrent synchronizer framework
Sci. Comput. Program., Elsevier North-Holland, Inc., 2005, 58, 293-309
• Auszüge
• Benchmark-Programm: Ein Faden ruft mit Wahrscheinlichkeit S gemeinsam
genutzten Zufallszahlengenerator auf, der durch Sperre geschützt wird. Mit
Wahrscheinlichkeit 1-S wird lokaler Zufallszahlengenerator benutzt
• Verschiedene Sperren ausprobiert
• Builtin: Synchronized-Konstrukt
• Mutex: Eigene, einfache Mutex-Klasse, die explizite Sperre implementiert
• Reentr: ReentrantLock
• fair: ReentrantLock im „fair“-Modus (d.h. länger wartende Fäden bevorzugt)
• Tests auf 4 x86-Maschinen (Linux) und 4 UltraSparc-Maschinen (Solaris 9)
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
11
Sperrkonstrukte
Performanzvergleich
Builtin: synchronized-Konstrukt
Mutex: explizite sperre
Reentr: ReentrantLock
fair: ReentrantLock im „fair“-Modus
• Overhead-Zeiten in ns
Name
1P
2P
2A
4P
1U
4U
8U
24U
builtin
18
58
13
116
90
122
160
161
mutex
9
71
21
95
40
82
83
84
reentr
31
77
31
109
58
100
103
108
fair
37
81
30
117
67
115
123
119
Ausführung mit 1 Faden
Zeit ist Differenz zwischen
Code mit Synchronisierung vs.
Code ohne Synchronisierung
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
builtin
521
930
748
1146
879
2590
1274
1983
mutex
46
108
79
188
153
347
157
160
reentr
67
132
84
247
177
368
174
182
fair
8327
14967
33910
15328
41394
30004
31084
32291
1P (1 × 900 MHz Pentium 3)
2P (2 × 1400 MHz Pentium 3)
2A (2 × 2000 MHz Athlon)
4P (2 × 2400 MHz hyperthreaded Xeon)
1U (1 × 650 MHz Ultrasparc2)
4U (4 × 450 MHz Ultrasparc2)
8U (8 × 750 MHz Ultrasparc3)
24U (24 × 750 MHz Ultrasparc3)
Overhead pro Sperre mit
S = 1 (immer gemeinsamer
Generator genutzt) und 256
parallelen Fäden
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
12
Klassen mit atomaren
Operationen
• java.util.concurrent.atomic
• Enthält Klassen mit atomare Operationen auf boolean,
integer, Referenztypen,…
• Beispiel:
AtomicInteger
• Atomar:
• compareAndSet(int expect, int update)
• addAndGet(int delta)
• getAndAdd(int delta)
• decrementAndGet()
• getAndIncrement()
…
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
13
Koordination: Konstrukte für Warten und
Benachrichtigung (1)
• Manchmal müssen Fäden ihre Ausführung stoppen (und
Sperren freigegen), bis ein bestimmtes Ereignis eintritt
und erst danach ihre Ausführung fortsetzen
• Methoden in java.lang.Object
public final void wait()
throws InterruptedException;
public final void notify();
public final void notifyAll();
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
14
Koordination: Konstrukte für Warten und
Benachrichtigung (2)
• Jedes Objekt verwaltet eine interne Warteschlange mit
wartenden Fäden
• Wenn ein Faden die wait-Methode eines Objekts aufruft, dann
• werden alle Sperren, die der Faden hält, temporär freigegeben
• Anschließend wird der Faden in die Warteschlange des Objekts
eingereiht und schlafen gelegt
• Wenn ein anderer Faden notifyAll beim selben Objekt
aufruft, dann weckt das Objekt alle Fäden in der Warteschlange
auf und ermöglicht ihnen, weiter ausgeführt zu werden
• notify() schickt Signal an irgendeine Aktivität aus dieser
Warteschlange
• notifyAll() schickt Signal an alle Aktivitäten dieser
Warteschlange
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
15
Beispiel zu Wait / NotifyAll
import java.util.*;
/**
* Eine Warteschlange. Ein Faden ruft put() auf um ein Objekt in die
* Schlange zu legen. Ein anderer Faden ruft get() auf um ein Objekt aus
* der Schlange zu nehmen. Wenn Schlange leer ist, wartet get(), bis ein
* Objekt da ist (d.h. bis Nachricht von notify da).
*/
public class WaitingQueue<E> {
LinkedList<E> q = new LinkedList<E>(); // Speichert Objekte
public synchronized void
q.add(o);
this.notifyAll();
}
put(E
o) {
// Füge Objekt am Ende der Liste hinzu
// Benachrichtige wartende Fäden,
// dass Objekt da
public synchronized E get() {
while(q.size() == 0) {
try { this.wait(); }
catch (InterruptedException ignore) {}
}
return q.remove(0);}
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
16
Ergänzungen in der Java-Bibliothek
java.util.concurrent
• Verwendung von expliziten bzw. feingranularen Sperren
oft fehleranfällig
• Viele der Datenstrukturen (z.B. Schlangen) sind im
parallelen Fall nicht verwendbar, wenn mehrere Fäden
simultan darauf arbeiten (engl. „not thread-safe“)
• Ab Java 1.5:
java.util.concurrent stellt weitere Klassen zur
parallelen Programmierung zur Verfügung
• Konzepte / Terminologie ähneln z.T. Ada
(vgl. Burns & Wellings, Concurrent and Real-Time Programming in Ada, Cambridge, 2007)
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
17
java.util.concurrent
• Bereitstellung nützlicher Funktionalität, die
„immer wieder“ gebraucht wird
• Datenstrukturen, die im parallelen Fall anwendbar sind
• Z.T. Konstrukte auf höherer Abstraktionsebene
• Kategorien
• Kollektionen („Collections“)
• Konstrukte zur asynchronen Ausführung, Thread Pools
• Synchronisierer („Synchronizers“)
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
18
java.util.concurrent
Concurrent Collections
• Eine Kollektion ist eine Gruppe von Objekten
• Für sequenzielle Verarbeitung bietet Java bereits im “Java
Collections Framework” (java.util) entsprechende Datenstrukturen,
z.B.
• (Hash)Set: Kollektion ohne Duplikate (Operationen: add, remove,
contains, ..)
• SortedSet: Set, in dem Elemente sortiert werden
• Verschiedene Set-Implementierungen basierend auf Hash-Tabellen,
Rot-Schwarz-Bäumen, Arrays, Bitfeldern
• (Array)List: Kollektion, in der Elemente eine Ordnung haben;
Duplikate sind erlaubt
• (Hash)Map: Menge von Schlüssel/Wert-Paaren
(Operationen: put(key, value), get(key), containsKey, …)
Operationen auf diesen Datenstrukturen sind nicht atomar
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
19
java.util.concurrent
Concurrent Collections
• Ab Java5: In java.util.concurrent zusätzliche
Kollektionsdatenstrukturen sowie atomare Operationen für sichere
Nutzung im parallelen Fall, z.B.:
• ConcurrentHashMap
• CopyOnWriteArrayList
• CopyOnWriteArraySet
• ConcurrentLinkedQueue
• Einige benutzen aus Performanzgründen keine synchronized-
Konstrukte, sondern explizite Sperren und volatile-Modifizierer
• (volatile bewirkt, dass ein Ergebnis nicht im Zwischenspeicher belassen wird,
sondern immer aktualisiert wird. Die parallelen ausgeführten Fäden sehen somit
immer den korrekten Variablenwert, da er vor jeder Benutzung aus dem Speicher
gelesen und nach einer Änderung sofort wieder zurückgeschrieben wird)
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
20
java.util.concurrent
Concurrent Collections
Beispiele
• ConcurrentHashMap
• Thread-sichere Implementierung der java.util.Map Schnittstelle
• Benutzt kein synchronized
• Beliebig viele parallele Leseoperationen ohne Sperren erlaubt
• Für Schreibzugriffe wird Datenstruktur intern in Segmente unterteilt, die
beim Aktualisieren für die Lese-und Schreibzugriffe anderer Fäden
gesperrt werden
• Größe der Segmente kann angepasst werden
• CopyOnWriteArrayList
• Thread-sichere Implementierung der java.util.List Schnittstelle
• Benutzt zur Implementierung ein Array
• Alle Update-Methoden benutzen synchronized
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
21
java.util.concurrent
Modell zur asynchronen Ausführung
Situation vor Java 1.5:
• Rückgabe eines Wertes von einem neu gestarteten
Faden an den aufrufenden Faden war umständlich
• Im Prinzip über gemeinsam genutzte Variable und
Synchronisation
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
22
java.util.concurrent
Modell zur asynchronen Ausführung
Neuer Ansatz ab Java 1.5
• Aufgerufener Faden implementiert die callable
Schnittstelle (d.h. es wird call-Methode anstatt run
implementiert)
• Objekt, das callable implementiert, repräsentiert eine Aufgabe, die ein
Ergebnis liefert und eine Ausnahme auslösen kann
• Aufrufender Faden übergibt ein Objekt, dass
callable implementiert, mittels submit() an einen
Executor und setzt danach seine Ausführung fort
•Submit liefert ein Future-Objekt zurück
• Aufrufer liest Ergebnis mittels get() aus Future-Objekt
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
public interface Callable<V> {
public V call() throws Exception;
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
23
}
java.util.concurrent
Modell zur asynchronen Ausführung
• Future
• Repräsentiert Ergebnis einer Berechnung, das sofort oder in der
Zukunft verfügbar sein wird
• Funktionalität wie bereits besprochen
• get() liefert das Ergebnis der Berechnung oder blockiert so
lange, bis das Ergebnis vorhanden ist
• Typische Nutzung: Future ist Ergebnis des asynchronen
Ausführens einer Callable<V> Aufgabe in einem
ExecutorService
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
public interface Future<V> {
public V get();
public V get(long timeout, TimeUnit unit);
public boolean cancel(boolean
mayInterruptIfRunning);
public boolean isCancelled();
public boolean isDone() ;
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
24
}
java.util.concurrent
Beispiel: Future
class CallableExample implements Callable<String> {
public String call() {
String result = “Arbeit fertig”;
// tue was
return result;
}
}
ExecutorService es = Executors.newSingleThreadExecutor();
Future<String> f = es.submit(new CallableExample());
//tue was in der Zwischenzeit
try {
String callableResult = f.get();
} catch (InterruptedException ie) {...}
catch (ExecutionException ee) {...}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
25
java.util.concurrent
Executors (1)
Executors führen Aufgaben mit Hilfe von Fäden aus
• Aufgaben werden in einer internen Schlange abgelegt
• Executor ist eine Schnittstelle, die die Methode execute enthält
• ExecutorService erweitert Executor um Verwaltungsmethoden wie
submit, shutdown, invokeAll, …
• Executors ist eine Fabrik, die verschiedene Implementierungen von
ExecutorService liefert
• Single Thread Executor:
• Fixed Thread Pool:
• Cached Thread Pool:
• Scheduled Thread Pool:
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Hat genau einen Arbeiterfaden
Thread Pool mit fester Anzahl von Fäden
Thread Pool, der Anzahl von Fäden je
nach Bedarf erzeugt
Erlaubt periodische Ausführung von
Aufgaben oder mit bestimmter
Verzögerung
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
26
java.util.concurrent
Executors (2) - Beispiel
class WebServer {
Executor pool = Executors.newFixedThreadPool(7);
public static void main(String[] args) {
ServerSocket socket = new ServerSocket(80);
while (true) {
final Socket connection = socket.accept();
Runnable r = new Runnable() {
public void run() {
handleRequest(connection);
}
};
pool.execute(r);
}
}
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
27
java.util.concurrent
Schlangen
Weitere Ergänzungen
• Blockierende Schlangen
Produzent
• Implementieren BlockingQueue-Schnittstelle
• Datenaustausch zwischen Fäden gemäß dem
Erzeuger-Verbraucher-Muster
• Blockierende Methoden: put, take
Blockierende
Schlange
• Erzeuger blockiert, wenn Schlange voll;
Verbraucher blockiert, wenn Schlange leer
• Auch zeitlich beschränke Blockierung durch
möglich
Konsument
• offer/poll blockieren nur für eine bestimmte Zeit
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
28
java.util.concurrent
Schlangen
• Verschiedene Implementierungen
• ArrayBlockingQueue
•
•
•
•
basiert auf Array mit fester Größe
DelayQueue
ordnet Elemente nach Wartezeiten an
LinkedBlockingQueue
basiert auf verketteter linearer Liste
PriorityBlockingQueue
Schlange mit unbegrenzter Kapazität, die Elemente gemäß einer
Vergleichsoperation anordnet
SynchronousQueue
basiert auf Schlange mit Kapazität 0. Gedacht als „Übergabe“
bzw. Rendezvous zwischen Fäden (put wartet bis take aufgerufen
wird oder umgekehrt).
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
29
java.util.concurrent
Beispiel: ArrayBlockingQueue
Beispiel
• Hauptfaden
• hat Schlange, die 10 Zahlen umfassen kann
• befüllt Schlange mit Zahlen
• erzeugt mehrere Arbeiterfäden
• Arbeiterfaden nimmt Zahl aus Schlange und
quadriert sie
• Blockiert, wenn Schlange leer
• Bricht ab, wenn spezielle Merkierung gelesen wird
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
30
java.util.concurrent
Beispiel: ArrayBlockingQueue
Hauptfaden
// Erzeuge ArrayBlockingQueue mit Integer
final int capacity = 10;
BlockingQueue<Integer> queue = new
ArrayBlockingQueue<Integer>(capacity);
// Erzeuge Arbeiterfäden
final int numWorkers = 2;
Worker[] workers = new Worker[numWorkers];
for (int i=0; i<workers.length; i++) {
workers[i] = new Worker(queue);
workers[i].start();
}
try {
//Füge Arbeit in Queue hinzu;
//blockiere, wenn voll
for (int i=1; i<100; i++) {
queue.put(i);
}
Arbeiter
class
Worker
extends Thread {
//Marker, wann Arbeit beenden
static final Integer
NO_MORE_WORK = new Integer(0);
BlockingQueue<Integer> q;
Worker(BlockingQueue<Integer> q) {
this.q = q;
}
public void run() {
try {while (true) {
//nimm nächste Zahl oder
//blockiere, wenn leer
Integer x = q.take();
//Abbruch, wenn Marker gefunden
if (x == NO_MORE_WORK) {break;}
//Füge Marker ein, die Worker Ende
// Arbeit
//signalisieren
int y = x * x;}
for (int i=0; i<workers.length; i++) {
} catch (InterruptedException e) {}
queue.put(Worker.NO_MORE_WORK);
}
Fakultät für Informatik
Prof. Walter F. Tichy, Dr. Victor Pankratius,
31
} Lehrstuhl für Programmiersysteme
} Dipl.-Inform. Frank Otto
} catch (InterruptedException e) {}
java.util.concurrent
Synchronisierer
Werden zur Synchronisation zwischen Fäden verwendet
• Semaphore
• Wird mit einer fixen Anzahl von “Genehmigungen” initialisiert;
• acquire blockiert, bis eine Genehmigung verfügbar ist und
dekrementiert anschließend #Genehmigungen
• Release inkrementiert #Genehmigungen
• Exchanger
• Ermöglicht Rendezvous und Datenaustausch zwischen zwei
Fäden mittels der exchange-Methode
• Jeder Faden ruft exchange mit einem Objekt auf (das
ausgetauscht werden soll) und bekommt nach dem Rendezvous
das vom anderen Faden übergebene Objekt
• Der zuerst ankommende Faden blockiert so lange, bis der zweite
exchange aufruft
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
32
java.util.concurrent
Synchronisierer - Beispiel: Exchanger
class FillAndEmpty {
Exchanger<DataBuffer> exchanger = new Exchanger();
DataBuffer initialEmptyBuffer = ...
DataBuffer initialFullBuffer = ...
class FillingLoop implements Runnable {
public void run() {
DataBuffer currentBuffer = initialEmptyBuffer;
try { while (currentBuffer != null) {
addToBuffer(currentBuffer);
if (currentBuffer.full()) currentBuffer =
Jeder Faden übergibt ein
Objekt an exchangeMethode und erhält das
vom jeweils anderen
Faden übergebene
Objekt.
exchanger.exchange(currentBuffer); } Idee:
} catch (InterruptedException ex) {...handle...}}
}
class EmptyingLoop implements Runnable {
public void run() {
DataBuffer currentBuffer = initialFullBuffer;
try { while (currentBuffer != null) {
takeFromBuffer(currentBuffer);
if (currentBuffer.empty()) currentBuffer =
exchanger.exchange(currentBuffer); }
•Puffer können zwischen
Fäden ausgetauscht
werden
•Faden, der Puffer füllt,
übergibt vollen Puffer an
Faden, der Puffer leert
} catch (InterruptedException ex) {...handle...} }
}
•Faden, der Puffer leert,
}
void start() { new Thread(new FillingLoop()).start();
übergibt leeren Puffer an
Fakultät
für
Informatik
new Thread(new EmptyingLoop()).start();
}
Prof. Walter F. Tichy, Dr. Victor Pankratius,
Dipl.-Inform. Frank Otto
33
Lehrstuhl für Programmiersysteme
Faden, der Puffer füllt
java.util.concurrent
Synchronisierer
• CyclicBarrier
• Synchronisiert Gruppe von n Fäden.
• Fäden rufen await()-Methode auf, die so lange blockiert, bis alle n
Fäden warten.
• Danach wird den Fäden erlaubt, ihre Ausführung fortzusetzen (die
Barriere wird zurückgesetzt).
• Erweiterung: Zusätzliche Runnable-Methode wird ausgeführt, wenn der
letzte von n Fäden await() aufgerufen hat.
• CountDownLatch
• Synchronisiert mehrere Fäden
• Jeder Faden ruft await() auf und blockiert, bis countDown() count
mal aufgerufen wurde
• Danach wird allen Fäden erlaubt, ihre Ausführung fortzusetzen
• Erneuter Aufruf von await() hat anschließend keinen Effekt mehr
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
34
java.util.concurrent
Beispiel: CountDownLatch
• Personen warten vor Eingangstür eines Einkaufszentrums mit mehreren
Geschäften
• Zunächst sind alle Geschäfte noch geschlossen, werden aber sukzessive
geöffnet (CountDown sukzessive aktualisiert)
• Erst wenn alle Geschäfte geöffnet haben, wird die Eingangstür zum
Einkaufszentrum geöffnet. Dann können die wartenden Personen ins
Einkaufszentrum gehen und ihre Einkäufe erledigen
wartende Fäden
(hier: Personen)
CountDownLatch
CountDownLatch
Aktiver Countdown-Faden
(hier: herunterzählen der noch
geschlossenen Geschäfte)
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
wartende Fäden
werden aktiviert,
sobald der
Countdown 0
erreicht hat
(hier: Personen
kaufen ein, sobald
alle Geschäfte
geöffnet haben)
35
java.util.concurrent
Synchronisierer - Beispiel: CountdownLatch
public class CountDownLatchSample {
private CountDownLatch latch;
private int shops = 5;
private class Shopper implements Runnable{
public void run() {
try {latch.await();}
catch (InterruptedException e) {...}
System.out.println("Juhu, shopping!");}
}
private class Shop implements Runnable {
public void run() {
System.out.println("Opening shop..");
latch.countDown();
private void simulate() {
int shopper = 10;
for (int i = 0; i < shopper; i++) {
Thread t=new Thread(new Shopper());
t.start();
}
for (int i = 0; i < shops; i++) {
Thread t = new Thread(new Shop());
t.start();
}
}
public static void main(...) {
new CountDownLatchSample().simulate();
}
}
}
}
public CountDownLatchSample() {
latch = new CountDownLatch(shops);
}
Fakultät für Informatik
Lehrstuhl für Programmiersysteme
Prof. Walter F. Tichy, Dr. Victor Pankratius, Dipl.-Inform. Frank Otto
36
Herunterladen