nebenläufigkeit in java print - inf.fu-berlin.de · java-applet java-applet main-thread...
TRANSCRIPT
NebenlNebenlääufigkeit in Javaufigkeit in Java
Prof. Dr. Prof. Dr. Margarita EspondaMargarita Esponda
Gliederung der VorlesungGliederung der Vorlesung
- Konzepte der Nebenläufigkeit
- Threads in Java
- Synchronisationsprobleme
- Klassische Lösungen
- Semaphoren
- Monitore
- Lebenszyklus eines Threads
WettersimulationBetriebssysteme
Suchmaschinen
Computerspiele
Wo finden wir NebenlWo finden wir Nebenlääufigkeit?ufigkeit?
GUIs
ParallelitParallelitäätt
Echte Parallelität Virtuelle Parallelität
Mehrere Prozesse laufen auf der selben CPU
Prozesse laufen auf unterschiedlichen CPUs
Prozess1Prozess1
Prozess2Prozess2
Prozess3Prozess3
Prozess1Prozess1
Prozess2Prozess2
Prozess3Prozess3
Prozess3Prozess3 Prozess3
Prozess3
Grundlegende BegriffeGrundlegende Begriffe
"single program""single program"
"task switching"
"multitasking"
"multithreading"
In der Steinzeit der PCs durfte man nur einzelne Programme streng sequentiell ausführen.
Mehrere Programme liegen im Hauptspeicher.
Durch Umschaltung setzt man die Ausführung eines der Programme fort.
Das Betriebssystem schaltet die Programme um. Man hat das Gefühl, dass mehrere Programme parallel laufen.
Es gibt mehrere Programmfäden, die parallel
innerhalb eines Programms ausgeführt werden.
"Multitasking" vs. "Multithreading""Multitasking" vs. "Multithreading"
mehrere Prozesse mehrere Prozesse ((processprocess))
jeder Prozess hat eine eigene Umgebung
Kein gemeinsamer Adressraum
Verwaltung durch das Betriebssystem
mehrere Programmfäden (thread)
alle Threads laufen in der gleichen Umgebung
gemeinsamer Adressraum !!!
Verwaltung innerhalb eines Prozesses
Multitasking + MultithreadingMultitasking + Multithreading
Prozess 1 Prozess 2 Prozess 3
Thread 1 Thread 2
Adressraumfür Prozess 1
Adressraumfür Prozess 2 Adressraum
für Prozess 3
MultitaskingMultitasking
Prozess1Prozess1
Betriebssystem
Prozess2Prozess2
Prozess3Prozess3
Lokaler SpeicherLokaler Speicher
Lokaler SpeicherLokaler Speicher
Lokaler SpeicherLokaler Speicher
Gemeinsamer Speicher
Gemeinsamer Speicher Prozesse werden direkt vom
Betriebssystem verwaltet.
Jeder Prozess bekommt einen eigenen Speicherbereich vom Betriebssystem zugeteilt.
Multitasking + MultithreadingMultitasking + Multithreading
JVMJVM
Java Virtuelle MaschineJava Virtuelle Maschine
Thread1Thread1 Lokaler SpeicherLokaler Speicher
Lokaler SpeicherLokaler SpeicherThread2Thread2
Lokaler SpeicherLokaler SpeicherThread3Thread3
Gemeinsamer Speicherbereich
Gemeinsamer Speicherbereich
Prozess1Prozess1
Betriebssystem
Prozess2Prozess2
Lokaler SpeicherLokaler Speicher
Lokaler SpeicherLokaler Speicher
Gliederung der VorlesungGliederung der Vorlesung
- Konzepte der Nebenläufigkeit
- Threads in JavaThreads in Java
- Synchronisationsprobleme
- Klassische Lösungen
- Semaphoren
- Monitore
- Lebenszyklus eines Threads
Ein Ein ThreadThread ist ein eigenstist ein eigenstäändiges Programmfragment, ndiges Programmfragment, das parallel zu anderen Programmfragmenten (das parallel zu anderen Programmfragmenten (ThreadsThreads) ) laufen kann.laufen kann.
Threads:Threads: kköönnen die Bedienbarkeit von nnen die Bedienbarkeit von Dialoganwendungen verbessern, indem rechenintensive Dialoganwendungen verbessern, indem rechenintensive Anwendungen im Hintergrund ablaufen.Anwendungen im Hintergrund ablaufen.
ThreadsThreads werden auch als werden auch als leichtgewichtigeleichtgewichtige ProzesseProzessebezeichnet.bezeichnet.
Threads Ausführungsstrang
Threads in JavaThreads in Java
Ein Programmfaden oder Ausführungsstrang wird durch
ein Objekt des Typs Thread repräsentiert.
Die Klasse Thread ist eine vollständige Implementierung
des Runnable-Interfaces.
Das Runnable-Interface stellt Klassen von Objekten
die parallel ausführbaren Programmcode beinhalten.
public interface Runnable {
public abstract void run();
}
Programmierung von ThreadsProgrammierung von Threads
Thread-Klassen können in Java auf zwei verschiedene
Arten definiert werden:
als Unterklasseder Thread-Klasse
durch Implementierungder Runnable-Schnittstelle
public class Counter extends Thread { . . .
public void run(){
. . .}
}
public class Counter implements Runnable{ . . .
public void run(){
. . .}
}
Die Methode run() muss überschriebenwerden
Die Methode run() muss implementiertwerden
DieDie ThreadThread--KlasseKlasse
Thread ( ); // erzeugt ein leeres Thread-Objekt mit
// automatisch festgelegtem Namen Thread-N
Thread ( String name );// erzeugt ein leeres Thread-Objekt mit Namen name
Thread ( Runnable target )
// erzeugt zu Runnable-Objektziel ein Thread-Objekt
Thread ( Runnable target, String name )
// erzeugt zu Runnable-Objektziel ein Thread-Objekt
// mit Namen name
Einige Konstruktoren
run()-Methode
Innerhalb der run()-Methode befinden sich die
potenziell parallel ausführbaren Aktivitäten
eines Threads.
start() - Methode
Startet ein Thread und zwar:
- es wird Speicher für den Thread bereit gestellt
- und die run-Methode wird aufgerufen
DieDie ThreadThread--KlasseKlasse
Beispiel:Beispiel: public class SimpleThread extends Thread {
public SimpleThread ( String name ) {super(name);
}
public void run(){for( int i=0; i<100; i++ )
System.out.print( this.getName() );}
}
public class TestSimpleThread {
public static void main( String[] args ){
SimpleThread tAnne = new SimpleThread("Anne ");
SimpleThread tPeter = new SimpleThread("Peter ");
tAnne.start();
tPeter.start();
}
}
Anne Anne Anne Anne Anne Anne Anne Anne Anne Anne AnnePeter Peter Peter Peter Peter Peter Peter Peter Peter Peter Peter Peter Peter Peter Peter Peter Anne Anne Anne Anne Anne Anne Anne Anne Anne Anne Anne Anne Anne Anne Anne Peter Peter Peter Peter Peter Peter . . . . . . . . . . .
JavaJava--Programm mit MultithreadingProgramm mit Multithreading
Zeit
main .....thread1 = new Thread()
thread2 = new Thread()thread1.start()
void run(){work1()work2()work3()
work4()work5()
}
thread2.start()
mainDoSomething()
mainWork()mainWork()end()
}
.
..
.
void run(){work1()
work2()work3()work4()
work5()work6()
}
thread1
thread2
join() - Methode
sleep(int millis) - Methode
Um auf die Beendigung eines oder mehrerer Threads
zu warten, benutzt man die join() - Methode.
Ein Thread kann mit der sleep()-Methode für eine
vorbestimmte Zeit in den Zustand "not runnable"
versetzt werden.
…… weitere wichtige Methodenweitere wichtige Methoden
Implementierung als Unterklasse von ThreadImplementierung als Unterklasse von Threadpublic class SimpleThread extends Thread {
int lifeTime;
public SimpleThread( String name, int lifeTime ) {super( name );this.lifeTime = lifeTime;
}
public void run() {for ( int i=0; i<lifeTime; i++ ) {
try { this.sleep( 1000 );System.out.println( "Ich bin "+this.getName() );
}catch ( InterruptedException ie )
System.out.println(ie);}
}
}
public class TestSimpleThread {
public static void main( String[] args ) {
SimpleThread t1 = new SimpleThread( "Andreas", 5 );
SimpleThread t2 = new SimpleThread( "Hanna", 5 );
SimpleThread t3 = new SimpleThread( "Anne", 3 );
t1.start();
t2.start();
t3.start();
System.out.println( "Ich bin main" );
}
}
Ich bin mainIch bin main
Ich bin AndreasIch bin Andreas
Ich bin HannaIch bin Hanna
Ich bin AnneIch bin Anne
Ich bin AndreasIch bin Andreas
Ich bin HannaIch bin Hanna
Ich bin AnneIch bin Anne
Ich bin AndreasIch bin Andreas
Ich bin HannaIch bin Hanna
Ich bin AnneIch bin Anne
Ich bin AndreasIch bin Andreas
Ich bin HannaIch bin Hanna
Ich bin AndreasIch bin Andreas
Ich bin HannaIch bin Hanna
maint1t2t3t1t2t3t1t2t3t1t2t1t2
Ausgabe:
ThreadThread--BeispielBeispiel
public class TestSimpleThread {
public static void main( String[] args ) {
SimpleThread t1 = new SimpleThread( "Andreas", 5 );SimpleThread t2 = new SimpleThread( "Hanna", 5 );t1.start();t2.start();try {
t1.join(); // Warte auf den 1.Threadt2.join(); // Warte auf den 2.Thread
}catch ( InterruptedException ie ) {
System.out.println( ie );}System.out.println( "Ich bin main" );
} // end of main} // end of class
Ich bin AndreasIch bin Andreas
Ich bin HannaIch bin Hanna
Ich bin AndreasIch bin Andreas
Ich bin HannaIch bin Hanna
Ich bin AndreasIch bin Andreas
Ich bin HannaIch bin Hanna
Ich bin AndreasIch bin Andreas
Ich bin HannaIch bin Hanna
Ich bin AndreasIch bin Andreas
Ich bin HannaIch bin Hanna
Ich bin mainIch bin main
t1
t2
t1
t2
t1
t2
t1
t2
t1
t2
main
garbage collector
garbage collector
Es gibt kein JavaEs gibt kein Java--Programm ohne Threads.Programm ohne Threads.
Java-Anwendung
Betriebssystem
Browser
Java-Applet Java-Appletmain-Thread
init-Thread init-Thread
Betriebssystem
setVisible(true)
event-dispatcher
GUI
Gliederung der VorlesungGliederung der Vorlesung
- Konzepte der Nebenläufigkeit
- Threads in Java
-- SynchronisationsproblemeSynchronisationsprobleme
- Klassische Lösungen
- Semaphoren
- Monitore
- Lebenszyklus eines Threads
Was ist das Problem mit Threads?Was ist das Problem mit Threads?
- es ist sehr einfach Threads in Java zu
programmieren
- es ist schwer Threads ohne Fehler zu
programmieren!
Was geschieht, wenn Threads
gemeinsame Variablen oder
Ressourcen benutzen?
x=y
Threads mit gemeinsamen DatenThreads mit gemeinsamen DatenT1
x=y
T2
T1: x = x + 1;
T2:x = x * 2;
T2:y = y * 2;
public void run(){..x = x + 1;y = y + 1;
.}
paint();
public void run(){..x = x * 2;y = y * 2;
.}
paint();
paint(); T2:T1: y = y + 1;
3, 34, 38, 38, 68, 68, 7
x y
SynchronisationsproblemeSynchronisationsprobleme
public class Asynchron extends Thread {
public static int zaehler = 0;
public void run() {
while ( zaehler<25 ) {
zaehler++;
System.out.print( this + " " );
System.out.println( zaehler );
}
}
public static void main( String args[] ) {
Thread t1 = new Asynchron();
Thread t2 = new Asynchron();
t1.start();
t2.start();
}
}
Klassenvariable
Gemeinsame
Variable für
alle Objekte
der Klasse
Asynchron.
SynchronisationsproblemeSynchronisationsprobleme
public void run() {while ( zaehler<25 ) {
zaehler++;System.out.print( this + " " );System.out.println( zaehler );
}}
public void run() {while ( zaehler<25 ) {
zaehler++;System.out.print( this + " " );System.out.println( zaehler );
}}
zaehler 0
t1 t2
SynchronisationsproblemeSynchronisationsprobleme
zaehler 6
t0 t1
public void run() {while ( zaehler<25 ) {
zaehler++;System.out.print( this + " " );System.out.println( zaehler );
}}
public void run() {while ( zaehler<25 ) {
zaehler++;System.out.print( this + " " );System.out.println( zaehler );
}}
78
SynchronisationsproblemeSynchronisationsproblemeThread[Thread-0,5,main] 1Thread[Thread-0,5,main] 2Thread[Thread-0,5,main] 3Thread[Thread-0,5,main] 4Thread[Thread-0,5,main] 5Thread[Thread-0,5,main] 6Thread[Thread-1,5,main] Thread[Thread-0,5,main] 88Thread[Thread-0,5,main] 9Thread[Thread-0,5,main] 10Thread[Thread-0,5,main] 11Thread[Thread-0,5,main] 12Thread[Thread-0,5,main] 13Thread[Thread-0,5,main] 14Thread[Thread-0,5,main] 15Thread[Thread-0,5,main] 16Thread[Thread-0,5,main] 17Thread[Thread-0,5,main] 18Thread[Thread-0,5,main] Thread[Thread-1,5,main] 2020Thread[Thread-0,5,main] Thread[Thread-1,5,main] 2222Thread[Thread-0,5,main] Thread[Thread-1,5,main] 24Thread[Thread-0,5,main] 25
SynchronisationsproblemeSynchronisationsprobleme
zaehler 24
t0 t1
public void run() {while ( zaehler<25 ) {
zaehler++;System.out.print( this + " " );System.out.println( zaehler );
}}
public void run() {while ( zaehler<25 ) {
zaehler++;System.out.print( this + " " );System.out.println( zaehler );
}}
SynchronisationsproblemeSynchronisationsprobleme
zaehler 24
t0 t1
public void run() {while ( zaehler<25 ) {
zaehler++;System.out.print( this + " " );System.out.println( zaehler );
}}
public void run() {while ( zaehler<25 ) {
zaehler++;System.out.print( this + " " );System.out.println( zaehler );
}}
2526
LLöösung:sung:
T1
public void run(){..x = x + 1;y = y + 1;
.}
paint();
T2
public void run(){..x = x * 2;y = y * 2;
.}
paint();
Kritischer Abschnitt
Kritischer Abschnitt
nur ein Thread im kritischen Abschnitt
Wechselseitiger Ausschluss muss gewährleistet werden.
kritischer Abschnitt
Wechselseitiger Ausschluss muss gewährleistet werden,
wenn gemeinsame Ressourcen benutzt werden.
Kritische AbschnitteKritische Abschnitte
simultaneous peripheral operations on line
Drucker-Spooler
Erster freier Platz der Warteschlange
QTail
Thread A
...adr = liest QTail
speichert Datei in adr
inkrementiert QTail
...
Thread B
...adr = liest QTail
speichert Datei in adr
inkrementiert QTail
...
Typisches Beispiel:
0 1 2 3 4
Klassisches Beispiel in der Literatur:
simultaneous peripheral operations on line
Drucker-Spooler
0 1 2 3
QTail
Thread A
...adr = liest QTail
speichert Datei in adr
inkrementiert QTail
...
Thread B
...adr = liest QTail
speichert Datei in adr
inkrementiert QTail
...
Unterbrechung
=4
Unterbrechung
4 5
44
Typisches Beispiel:simultaneous peripheral operations on line
Drucker-Spooler
0 1 2 3
QTail
Thread A
...adr = liest QTail
speichert Datei in adr
inkrementiert QTail
...
Thread B
...adr = liest QTail
speichert Datei in adr
inkrementiert QTail
...Unterbrechung
4 5
Kritischer Abschnitt
Unterbrechung
6
Gliederung der VorlesungGliederung der Vorlesung
- Konzepte der Nebenläufigkeit
- Threads in Java
- Synchronisationsprobleme
-- Klassische LKlassische Löösungensungen
- Semaphoren
- Monitore
- Lebenszyklus eines Threads
Kritische AbschnitteKritische AbschnitteKritische Abschnitte sind die Teile des Programms, in denen auf gemeinsam benutzten Speicher bzw. Ressourcen zugegriffen werden kann.
Wechselseitiger Ausschluss muss gewährleistet werden.
1. Unterbrechungen ausschalten
2. Variablen sperren
3. Strikter Wechsel
4. Petersons Lösung
5. Die TSL- Anweisung
Wie?
1. Unterbrechungen ausschalten
Jedoch: Benutzerprozesse sollten nicht die Macht haben, alle Unterbrechungen auszuschalten.
Die Ausschaltung von Unterbrechungen ist ein Privileg des Betriebssystems.
Nicht geeignet als Ausschlussmechanismus für Benutzerprozesse.
disable_Interrupts();
kritischer_abschnitt();
enable_Interrupts();
2. Variablen sperren
Warteschlange
Sperre = 0
Wenn Sperre = 0, ist die Warteschlange gesperrt
Wenn Sperre = 1, ist die Warteschlange nicht gesperrt
Nehmen wir an, zwei Threads möchten eine Warteschlange
gemeinsam benutzen.
Die Prozesse benutzen wiederum eine gemeinsame Variable, um den Zugriff auf die Warteschlange zu synchronisieren.
2. Variablen sperren
Warteschlange
Sperre =
Thread A Thread B
if (Sperre == 0)
Sperre = 1;
kritischer
Abschnitt
wird
ausgeführt
else
warten....
if (Sperre == 0)
Sperre = 1;
kritischer
Abschnitt
wird
ausgeführt
else
warten....
Interrupt
0
2. Variablen sperren
Warteschlange
Sperre =
Thread A Thread B
if (Sperre == 0)
Sperre = 1;
kritischer
Abschnitt
wird
ausgeführt
else
warten....
if (Sperre == 0)
Sperre = 1;
kritischer
Abschnitt
wird
ausgeführt
else
warten....
Interrupt
Interrupt
1
2. Variablen sperren
Warteschlange
Sperre =
Thread A Thread B
if (Sperre == 0)
Sperre = 1;
kritischer
Abschnitt
wird
ausgeführt
else
warten....
if (Sperre == 0)
Sperre = 1;
kritischer
Abschnitt
wird
ausgeführt
else
warten....
Interrupt
1
Beide Prozesse können in ihren
kritischen Bereich
gleichzeitig eintreten.
3. Strikter Wechsel
turn = 0
while ( true ) {
while ( turn != 0 );
critical_region();
turn = 1;
noncritical_region();
}
while ( true ) {
while ( turn != 1 );
critical_region();
turn = 0;
noncritical_region();
}
Warteschlange
Thread 0 Thread 1
3. Strikter Wechsel
turn = 0
while ( true ) {
while ( turn != 0 );
critical_region();
turn = 1;
noncritical_region();
}
while ( true ) {
while ( turn != 1 );
critical_region();
turn = 0;
noncritical_region();
}
Warteschlange
Thread 0 Thread 1
3. Strikter Wechsel
turn = 1
while ( true ) {
while ( turn != 0 );
critical_region();
turn = 1;
noncritical_region();
}
while ( true ) {
while ( turn != 1 );
critical_region();
turn = 0;
noncritical_region();
}
Warteschlange
Thread 0 Thread 1
3. Strikter Wechsel
turn = 1
while ( true ) {
while ( turn != 0 );
critical_region();
turn = 1;
noncritical_region();
}
while ( true ) {
while ( turn != 1 );
critical_region();
turn = 0;
noncritical_region();
}
Warteschlange
Thread 0 Thread 1
3. Strikter Wechsel
Leider erfordert diese Lösung einen strikten Wechsel zwischen den Prozessen.
while ( true ) {
while ( turn != 0 );
critical_region();
turn = 1;
noncritical_region();
}
while ( true ) {
while ( turn != 1 );
critical_region();
turn = 0;
noncritical_region();
}
turn = 1
Warteschlange
Thread 0 Thread 1
Erst wenn Thread B wieder in seinem kritischen Abschnitt gewesen ist, darf Thread A seinen kritischen Abschnitt wieder betreten.
4. Petersons Lösung für zwei Prozessepublic class PetersonThread extends Thread {
static int turn = 0;static boolean[] ready = { false, false };
int id, other;
public PetersonThread( int id ){this.id = id;this.other = 1-id;
}
public void run() {while(true){
ready[id] = true;turn = other;while( ready[other] && turn==other );critical_region();ready[id]=false;noncritical_region();
}}
}
4. Petersons Lösung für zwei Prozesse
ready
0 1
false false turn =
public void run() {
while ( true ) {
ready[0] = true ;
turn = 1;
while(ready[1] && turn==1);
{ //kritischer Abschnitt }
ready[0] = false;
{ //Rest des Programms }
}
}
public void run() {
while ( true ) {
ready[1] = true ;
turn = 0;
while(ready[0] && turn==0);
{ //kritischer Abschnitt }
ready[1] = false;
{ //Rest des Programms }
}
}
0
Thread 0 Thread 1
4. Petersons Lösung für zwei Prozesse
ready
0 1
true false turn =
public void run() {
while ( true ) {
ready[0] = true ;
turn = 1;
while(ready[1] && turn==1);
{ //kritischer Abschnitt }
ready[0] = false;
{ //Rest des Programms }
}
}
public void run() {
while ( true ) {
ready[1] = true ;
turn = 0;
while(ready[0] && turn==0);
{ //kritischer Abschnitt }
ready[1] = false;
{ //Rest des Programms }
}
}
1
Thread 0 Thread 1
4. Petersons Lösung für zwei Prozesse
ready
0 1
true turn =
public void run() {
while ( true ) {
ready[0] = true ;
turn = 1;
while(ready[1] && turn==1);
{ //kritischer Abschnitt }
ready[0] = false;
{ //Rest des Programms }
}
}
public void run() {
while ( true ) {
ready[1] = true ;
turn = 0;
while(ready[0] && turn==0);
{ //kritischer Abschnitt }
ready[1] = false;
{ //Rest des Programms }
}
}
0false
Thread 0 Thread 1
5. TSL-Anweisung
Insbesondere Mehrprozessorrechner haben TSL-Anweisungen.
TSL RX, LOCK Test and Set Lock
Wenn die CPU eine TSL-Anweisung im Speicher ausführt, wird der Speicherbus gesperrt, bis er fertig ist.
Lösung mit Hardware-Unterstützung.
Peterson + TSL-Anweisung
while ( true ) {
flag[0] = true ;
turn = 1;
while(flag[1] && turn==1);
{ //kritischer Abschnitt }
flag[0] = false;
{ //Rest des Programms }
}
while ( true ) {
flag[1] = true ;
turn = 0;
while(flag[0] && turn==0);
{ //kritischer Abschnitt }
flag[1] = false;
{ //Rest des Programms }
}
P0 hat eine höhere Priorität P1 hat eine niedrigere Priorität
Prioritätsumkehrproblem
flag
0 1
false false turn = 0
Peterson + TSL-Anweisung
while ( true ) {
flag[0] = true ;
turn = 1;
while(flag[1] && turn==1);
{ //kritischer Abschnitt }
flag[0] = false;
{ //Rest des Programms }
}
while ( true ) {
flag[1] = true ;
turn = 0;
while(flag[0] && turn==0);
{ //kritischer Abschnitt }
flag[1] = false;
{ //Rest des Programms }
}
P0 hat eine höhere Priorität P1 hat eine niedrigere Priorität
Prioritätsumkehrproblem
flag
0 1
true true turn = 1
Peterson + TSL-Anweisung
Der Peterson-Algorithmus und die TSL-Lösung haben
den Nachteil, dass aktives Warten erforderlich ist.
1. CPU-Zeit Verschwendung
2. PrioritätsumkehrproblemProbleme
Prioritätsumkehrproblem
Obwohl P0 eine höhere Priorität als P1 hat, muss er
immer länger als P1 warten, um in seinen kritischen
Abschnitt eintreten zu können.
Schlafen und AufweckenSleep und Wakeup
Eine Alternative zum aktiven Warten ist:
Schlafen gehen, anstatt CPU-Zeit zu verschwenden.
Aber ein schlafender Prozess kann sich selber
nicht aufwecken. D.h. er braucht einen
entsprechenden Partner, der ihn wieder aufweckt.
Gliederung der VorlesungGliederung der Vorlesung
- Konzepte der Nebenläufigkeit
- Threads in Java
- Synchronisationsprobleme
- Klassische Lösungen
-- SemaphorenSemaphoren
- Monitore
- Lebenszyklus eines Threads
Semaphoren
Semaphoren sind eine der wichtigsten Datenstrukturen, die für die Synchronisation von Prozessen in fast allen Betriebssystemen zur Verfügung gestellt werden.
Semaphoren als eine Lösung für Prozesssynchronisation wurde von Edsger W. Dijkstra 1965 konzipiert.
Semaphoren haben folgende Komponenten:
- ein Zähler
- eine acquire-Operation
- eine release-Operation
Semaphoren
Der Inhalt der Semaphoren wird nur mit
Hilfe der Operationen acquire und release
verändert.
Die aquire- und release-Operationen sind
atomare Operationen, die einen Thread
eventuell wecken oder zum Schlafen
schicken.
Lösung mit Semaphoren
Semaphore sem = new Semaphore(1);. . .public void run(){
. . .sem.acquire();kritische_abschnitt();sem.release();. . .
}. . .
Ab Java 1.5 ist eine Semaphor-Klasse in dem Paket java.util.concurrent enthalten.
Allgemeine Verwendung eines einfachen binären
Semaphors oder mutex.
Probleme mit SemaphorenProbleme mit Semaphoren
s.release();
. . .
// Kritischer Abschnitt
. . .
s.acquire();
Mehrere Threads können in den kritischen Abschnitt eintreten.
s.acquire();
. . .
// Kritischer Abschnitt
. . .
s.acquire();
Ein Deadlockfindet innerhalb des Threads statt.
Folgende einfache Fehler werden oft vom Programmierer gemacht:
Probleme mit SemaphorenProbleme mit Semaphoren
S1.acquire();
S2.acquire();
.
.
.
S2.release();
S1.release();
T0 T1
S2.acquire();
S1.acquire();
.
.
.
S1.release();
S2.release();
Folgende Fehler sind im Programm schwer zu erkennen, weil die Probleme nur bei bestimmten Ausführungssequenzen auftreten.
S1.acquire();
S2.acquire();
T0:
T1:
T0:
T1:
S2.acquire();
S1.acquire();
Wartet!
Wartet!
Verklemmung!Verklemmung!
Gliederung der VorlesungGliederung der Vorlesung
- Konzepte der Nebenläufigkeit
- Threads in Java
- Synchronisationsprobleme
- Klassische Lösungen
- Semaphoren
-- MonitoreMonitore
- Lebenszyklus eines Threads
MonitoreMonitore
Gemeinsame Daten
Sind abstrakte Datentypen (ADT) Ta Tb Tc Td
.
.
.
Operationen
Ein Monitor garantiert gegenseitigen Ausschluss des Zugriffs auf die Daten innerhalb des Monitors.
Nur durch die Operationen des Monitors dürfen die inneren Daten geändert werden. Nur ein Thread darf
zu einem bestimmten Zeitpunkt innerhalb des Monitors aktiv sein.
MonitoreMonitore
To
Das Objekt ist blockiert
T3 T2 T4 T8 T1
Besitzer des Objektes
Nur ein Thread darf zu einem bestimmten Zeitpunkt innerhalb des Monitors aktiv sein.
Monitore können in Java als Klassen mit synchronized-
Methoden und geeigneter Verwendung der wait-, notify- und
notifyAll-Methoden realisiert werden.
Das Das synchronizedsynchronized--SchlSchlüüsselwortsselwort in Javain Java
In Java ist jede Instanz der Klasse java.lang.Objectmit einer Sperrvariable verknüpft.
Diese Sperre entspricht einem booleschen Semaphor.
. . .synchronized ( nums ) {
for ( int i=0; i<nums.length; i++ ) {if (nums[i] < 0)
nums[i] = -nums[i];}
}. . .
Beispiel:
. . .synchronized (Objektvariable) {
. . .}. . .
Das Das synchronizedsynchronized--SchlSchlüüsselwortsselwort in Javain Java
T1
. . .synchronized (A) {
. . .synchronized (B) {
. . .}
}. . .
T2
. . .synchronized (B) {
. . .synchronized (A) {
. . .}
}. . .
Verklemmung!
MonitoreMonitore
Gemeinsame Daten
Ta Tb Tc Td
Bedingungsvariablen
b1
b2
b3
T2 T1 T3
.
.
.
Warteschlangen, die mit Bedingungsvariablen verbunden sind.
Sprachen mit Monitorkonzept
Concurrent Pascal
C#
Erlang
Ada
Squeak Smalltalk
Java
T7
T4 T5
WaitWait undund NotifyNotify
Die wait() und notify()-Methoden können nur innerhalb eines synchronized-Blockes stehen.
Aufruf der wait-Methode
- Der Thread gibt die Objektschlüssel zurück.
- Der Thread selber geht in den blockierten Zustand.
- Der blockierte Thread wird in die Warteschlangedes Objektes gestellt.
Aufruf der notify-Methode
- Ein beliebiger Thread aus der Warteschlange des Objektes wird gewählt.
- Der gewählte Thread wird in den Entry-Set gestellt.
- Der Zustand des Threads wird auf runnable gesetzt.
Monitore in JavaMonitore in Java
To
Das Objekt ist blockiert
T3
Besitzer des Objektes
T2 T4T8 T1T8 T1
Entry-Set Wait-Set
Hier warten die Threads auf den Lock des Objektes
Hier warten die Threads auf ein Notify
wait
Monitore in JavaMonitore in Java
To
Das Objekt ist blockiert
T3
Besitzer des Objektes
T2 T4T8 T1T8 T1
Entry-Set Wait-Set
Hier warten die Threads auf den Lock des Objektes
Hier warten die Threads auf ein Notify
notify
Leser/SchreiberLeser/Schreiber--ProblemProblem
public class Database implements ReadWriteLock {
private int readerCounter;
private boolean Writing;
public Database(){
readerCounter = 0;
Writing = false;
}
. . .
}//end of class Database
- beliebig viele Threads dürfen gleichzeitig lesen
- nur ein Thread darf schreiben (keiner darf lesen)
Leser/SchreiberLeser/Schreiber--ProblemProblempublic class Database implements ReadWriteLock {
. . .
public synchronized void acquireReadLock() {
while( Writing == true ){
try {
wait();
} catch (InterruptedException e) {. . .}
}
++readerCounter;
}
public synchronized void acquireWriteLock() {
while( readerCounter>0 || Writing==true ){
try {
wait();
} catch (InterruptedException e) {. . .}
}
Writing = true;
}
}//end of class Database
Leser/SchreiberLeser/Schreiber--ProblemProblem
public class Database implements ReadWriteLock {
. . .
public synchronized void releaseReadLock() {
--readerCounter;
/* der letzte Leser meldet sich */
if ( readerCounter==0 )
notify();
}
public synchronized void releaseWriteLock() {
Writing = false;
notifyAll();
}
. . .
}//end of class Database
Verhungern!
Gliederung der VorlesungGliederung der Vorlesung
- Konzepte der Nebenläufigkeit
- Threads in Java
- Synchronisationsprobleme
- Klassische Lösungen
- Semaphoren
- Monitore
-- Lebenszyklus eines ThreadsLebenszyklus eines Threads
NewNew
new Thread()
rechenrechen--bereitbereit
TotTot
start()
stop()
blockiertblockiertresume()
stop()
suspend()
LebensLebens--Zyklus einesZyklus eines ThreadThreadss JDK 1.1JDK 1.1
stop()
Deadlock-Probleme!
kritischer Abschnitt
Verklemmungsprobleme
stop
Verklemmung!
rechenrechen--bereitbereit
new Thread()
rechnendrechnend
MonitorMonitor--blockiertblockiert
start()tottot
LebensLebens--Zyklus einesZyklus eines ThreadThreadss JDK 1.2JDK 1.2
wartendwartend
schlafendschlafendIOIO--
blockiertblockiert
neuneu
yield()
SchedulingScheduling
terminiert
wait()
notify()
interrupt
interrupt
Frei-gegeben
Monitorbesetzt
Timeout IO-Operation
IO-End
sleep()
java.util.concurrentjava.util.concurrent
- Klassen mit unteilbarem (atomarem) Zugriff
AtomicBoolean, AtomicInteger, AtomicIntegerArray,AtomicLong, AtomicReference, usw.
- Erweiterte Sammlungsklassen für Threads
ConcurrentLinkedQueue, ConcurrentHashMap, usw.
- Semaphor-Klasse
- Klassen für ThreadPools
- Erweiterte Klassen für Sperren und Synchronisation
LiteraturLiteratur
Operating System Concepts with Java. 7th Edition. 2007
Silverschatz, Galvin und Gagne
Java Threads. 3th Edition. 2004
Scott Oaks & Henry Wong.
FragenFragen