runnable

Werbung
Software Engineering für moderne, parallele Plattformen
5. Parallelität in Java
Dr. Victor Pankratius
Dr. Victor Pankratius
IPD Tichy- Lehrstuhl für Programmiersysteme
KIT – die Kooperation von Forschungszentrum Karlsruhe GmbH und Universität Karlsruhe (TH)
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
2
Dr. Victor Pankratius
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
…
}
3
Dr. Victor Pankratius
Thread implements Runnable {
Thread(String name);
Thread(Runnable target)
void start();
void run();
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()
4
Dr. Victor Pankratius
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();
5
Dr. Victor Pankratius
• 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
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();
6
Dr. Victor Pankratius
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
7
Dr. Victor Pankratius
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
}
8
Dr. Victor Pankratius
Alternative:
...
/*synchronisierter block*/
synchronized (obj) {
// kritischer Abschnitt
}
...
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
//Rekursion
…
lock.lock();
…
lock.unlock();
9
Dr. Victor Pankratius
auch bei
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, 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
10
Dr. Victor Pankratius
Sperrkonstrukte
Performanzvergleich
Doug Lea:
The java.util.concurrent synchronizer framework
Science of Computer Programming, 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.
Zweck der Randomisierung
Zeitpunkt, wann Sperre gesetzt wird
Code in Schleifen kann nicht trivialerweise optimiert werden
Tests auf 4 x86-Maschinen (Linux 2.4) und 4 UltraSparc-Maschinen (Solaris
9), SUN J2SE 5.0 JDK; alle Programme wurden vor den Messungen 20x
ausgeführt
11
Dr. Victor Pankratius
Sperrkonstrukte
Performanzvergleich
Auszüge (fortgesetzt)
Experimente mit verschiedenen Typen von Sperren
Builtin: Blockbasiertes Synchronized-Konstrukt
Mutex: Eigene, einfache Mutex-Klasse, die eine explizite Sperre
implementiert
Reentr: ReentrantLock
Faden, der die Sperre hält, kann Sperrmethoden wieder aufrufen.
Diese kehren ohne Synchronisierungsaufwand sofort zurück.
getHoldCount() gibt an, wie oft der Faden gesperrt hat; beim
Freigeben muss unlock() muss ebenso oft aufgerufen werden
fair: ReentrantLock im „fair“-Modus
Bevorzugt länger wartende Fäden beim Zuteilen der Sperre
12
Dr. Victor Pankratius
Sperrkonstrukte
Performanzvergleich
Builtin: synchronized-Konstrukt
Mutex: explizite sperre
Reentr: ReentrantLock
fair: ReentrantLock im „fair“-Modus
Schätzungen der Overhead-Zeiten in ns
Name
builtin
mutex
reentr
fair
builtin
mutex
reentr
fair
1P
2P
2A
4P
1U
4U
8U
24U
18
58
13
116
90
122
160
161
9
71
21
95
40
82
83
84
31
77
31
109
58
100
103
108
37
81
30
117
67
115
123
119
521
930
748
1146
879
2590
1274
1983
46
108
79
188
153
347
157
160
67
132
84
247
177
368
174
182
8327
14967
33910
15328
41394
30004
31084
32291
Overhead der Sync.-Konstrukte bei
Ausführung mit 1 Faden
Zeit ist Differenz zwischen Code mit
Synchronisierung (S=1) vs. Code
ohne Synchronisierung (S=0)
13
Dr. Victor Pankratius
Testrechner
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)
Mehraufwand (Overhead) pro Sperre bei
S = 1 (jeder Faden ruft immer gemeinsamen
Generator auf) und 256 parallelen Fäden
Klassen mit atomaren Operationen
java.util.concurrent.atomic
Enthält Klassen mit atomaren Operationen auf Datentypen wie Boolean,
Integer, Referenztypen
Beispiel:
AtomicInteger
Atomar ausführbare Operationen
compareAndSet(int expect, int update)
addAndGet(int delta)
getAndAdd(int delta)
decrementAndGet()
getAndIncrement()
…
14
Dr. Victor Pankratius
Koordination: Konstrukte für Warten und
Benachrichtigung (1)
Manchmal müssen Fäden ihre Ausführung stoppen (und Sperren
freigeben), 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();
15
Dr. Victor Pankratius
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 o aufruft, dann
wird die mit o assoziierte Sperre, die der Faden hält, temporär freigegeben
anschließend wird der Faden in die Warteschlange des Objekts o eingereiht und
schlafen gelegt
Wenn ein anderer Faden notifyAll auf demselben Objekt o aufruft,
dann weckt o alle Fäden in der Warteschlange auf und ermöglicht ihnen
die weitere Ausführung
notify() schickt Signal an irgendeine Aktivität aus dieser Warteschlange
notifyAll() schickt Signal an alle Aktivitäten dieser Warteschlange
16
Dr. Victor Pankratius
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);}
}
17
Dr. Victor Pankratius
Ergänzungen in der Java-Bibliothek
java.util.concurrent
Die Verwendung von expliziten bzw. feingranularen Sperren ist oft
fehleranfällig
Viele der Datenstrukturen (z.B. Schlangen) aus dem sequenztiellen
Fall 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)
18
Dr. Victor Pankratius
java.util.concurrent
Bereitstellung nützlicher Funktionalität, die „immer wieder“ gebraucht
wird
Kategorien
Kollektionen („Collections“)
Konstrukte zur asynchronen Ausführung, Thread Pools
Synchronisierer („Synchronizers“)
19
Dr. Victor Pankratius
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.
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
List: Kollektion, in der Elemente eine Ordnung haben;
Duplikate sind erlaubt
Map: Menge von Schlüssel/Wert-Paaren
(Operationen: put(key, value), get(key), containsKey, …)
Operationen auf diesen Datenstrukturen sind nicht atomar
20
Dr. Victor Pankratius
java.util.concurrent
Concurrent Collections
Ab Java5: java.util.concurrent bietet 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 synchronizedKonstrukte, 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. Für details
(insb. Zusammenhang zu „happens-before“-Relation) vgl. Beschreibung des JavaSpeichermodells.
21
Dr. Victor Pankratius
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
22
Dr. Victor Pankratius
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
23
Dr. Victor Pankratius
java.util.concurrent
Modell zur asynchronen Ausführung
Neuer Ansatz ab Java 1.5
Der aufgerufene Faden implementiert die callable Schnittstelle (d.h. es
wird die call-Methode anstatt run implementiert)
Objekt, das callable implementiert, repräsentiert eine Aufgabe, die ein Ergebnis liefert und
eine Ausnahme auslösen kann
Der aufrufende Faden übergibt ein Objekt, das 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
public interface Callable<V> {
public V call() throws Exception;
}
24
Dr. Victor Pankratius
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 der asynchronen Ausführung einer
Callable<V> Aufgabe in einem ExecutorService
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() ;
}
25
Dr. Victor Pankratius
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) {...}
26
Dr. Victor Pankratius
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; enthält die Methode execute
ExecutorService erweitert Executor um Verwaltungsmethoden wie
submit, shutdown, invokeAll, …
Executors ist eine Fabrik, die verschiedene Implementierungen von
ExecutorService liefert
27
Single Thread Executor:
Hat genau einen Arbeiterfaden
Fixed Thread Pool:
Thread Pool mit fester Anzahl von Fäden
Cached Thread Pool:
Thread Pool, der Anzahl von Fäden je
nach Bedarf erzeugt
Scheduled Thread Pool:
Erlaubt periodische Ausführung von
Aufgaben oder mit bestimmter
Verzögerung
Dr. Victor Pankratius
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);
}
}
}
28
Dr. Victor Pankratius
java.util.concurrent
Schlangen
Weitere Ergänzungen
Produzent
Blockierende Schlangen
Implementieren BlockingQueue-Schnittstelle
Datenaustausch zwischen Fäden gemäß dem Erzeuger-VerbraucherMuster
Blockierende
Blockierende Methoden: put, take
Erzeuger blockiert, wenn Schlange voll; Verbraucher blockiert, wenn
Schlange leer
Schlange
Auch zeitlich beschränke Blockierung möglich
offer/poll blockieren nur für eine bestimmte Zeit
Konsument
29
Dr. Victor Pankratius
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).
30
Dr. Victor Pankratius
java.util.concurrent
Beispiel: ArrayBlockingQueue
Beispiel
Hauptfaden
hat eine Schlange, die 10 Zahlen umfassen kann
befüllt die Schlange mit Zahlen
erzeugt mehrere Arbeiterfäden
Arbeiterfaden nimmt eine Zahl aus der Schlange und quadriert sie
Blockiert, wenn Schlange leer
Bricht ab, wenn spezielle Markierung gelesen wird
31
Dr. Victor Pankratius
java.util.concurrent
Beispiel: ArrayBlockingQueue
Arbeiter
class
Worker
Hauptfaden
extends Thread {
//Marker zum Beenden der Arbeit
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;}
// Arbeit
int y = x * x;}
} catch (InterruptedException e) {}
}
32
}
Dr. Victor Pankratius
// 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);
}
//Füge Marker ein, die Worker Ende
//signalisieren
for (int i=0; i<workers.length; i++) {
queue.put(Worker.NO_MORE_WORK);
}
} 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 die Anzahl der Genehmigungen
Release inkrementiert die Anzahl der Genehmigungen
33
Dr. Victor Pankratius
java.util.concurrent
Synchronisierer
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
34
Dr. Victor Pankratius
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); }
} catch (InterruptedException ex) {...handle...} }
35
}
}
void start() { new Thread(new FillingLoop()).start();
new Thread(new
EmptyingLoop()).start(); }
Dr. Victor Pankratius
•Puffer können zwischen
Fäden ausgetauscht
werden
•Faden, der Puffer füllt,
übergibt vollen Puffer an
Faden, der Puffer leert
•Faden, der Puffer leert,
übergibt leeren Puffer an
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.
36
Dr. Victor Pankratius
java.util.concurrent
Synchronisierer
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
37
Dr. Victor Pankratius
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
Aktiver Countdown-Faden
(hier: herunterzählen der noch
geschlossenen Geschäfte)
38
Dr. Victor Pankratius
CountDownLatch
wartende Fäden
werden aktiviert,
sobald der
Countdown 0
erreicht hat
(hier: Personen
kaufen ein, sobald
alle Geschäfte
geöffnet haben)
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();
public static void main(...) {
new CountDownLatchSample().simulate();
}
}
}
}
public CountDownLatchSample() {
latch = new CountDownLatch(shops);
39}
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();
}
}
Dr. Victor Pankratius
Herunterladen