ThreadSynchronisation
Thread Synchronisation in JAVA
0055060, Angelika Brückl
ThreadSynchronisation
Überblick - Interne Architektur der JVM
ThreadSynchronisation
Thread Synchronisation und Monitore (1)
• Monitor
Objekt, das einen Thread blockieren und von der Verfügbarkeit einer Ressource benachrichtigen kann
„Gebäude“ mit drei Räumen
• „Eingangshalle“ Thread erreicht Anfang des gegenseitigen Ausschlusses
• „Behandlungsraum“ gegenseitiger Ausschluss wird behandelt
• „Warteraum“ Wartepause bei Kooperation
„Eingangshalle“ „Behandlungsraum“ „Warteraum“
ThreadSynchronisation
Thread-Synchronisation und Monitore (2)
Gegenseitiger Ausschluss (mutual exclusion)
• Mehrere Threads arbeiten exklusiv mit gemeinsamen Daten
• Unterstützt mittels Object Locks
Kooperation
• Mehrere Threads arbeiten in Kooperation zusammen
• Unterstützt mittels wait und notify Methoden der Klasse object
1.
Enter the entry set -> „Gebäude über Eingangshalle betreten“2. Acquire the monitor -> „Behandlungsraum betreten u. benützen 3. Release the monitor and enter the wait set -> „Warteraum aufsuchen“
4. Acquire again a monitor -> „Behandlungsraum wieder benutzen“
5. Release and exit the monitor -> „Gebäude verlassen“
ThreadSynchronisation
Thread-Synchronisation und Monitore (3)
• Critical Regions (kritische Abschnitte)
Auszuführender Code hat automare Operation
• Kein anderer Thread darf den gleichen Monitor zwischenzeitlich benutzen
• Operation soll entweder ganz oder gar nicht ausgeführt werden
• Nur die Operationen 1) Enter the entry set und 5) release and exit the monitor sind ausführbar
• Operation 2) Acquire the monitor nur nach Operation 5) Realease and exit the monitor
• Thread Scheduling
Java verwendet fixen Priority-Scheduling-Algorithmus
Thread mit höherer Priorität wird zuerst ausgeführt
Theads mit gleicher Priorität werden mit Round-Robin-Verfahren
gescheduled – (OS muss time-slicing unterstützen)
ThreadSynchronisation
Thread-Synchronisation und Monitore (4)
• Mit dem Schlüsselwort synchronized werden in Java Monitore
gekennzeichnet
• Bytecode:
monitorenter
(Beginn synchronisierter Code-Block)• Anfordern der objectref
• Durchführung Operation 1) Enter the entry set
• Durchführung Operation 2) Acquire the monitor, falls kein Thread Owner dieses Monitors ist
monitorzähler = monitorzähler + 1
• Sonst Einordnung in Entry Set
monitorexit
(Ende synchronisierter Code-Block)• Freigeben der objektref
• monitorzähler = monitorzähler -1
• Durchführung Operation 5) Release and exit the monitor, falls monitorzähler zu Null wird
• Sonst Durchführung des Operationen 2) Acquire the monitor oder 4) Acquire again the monitor abhängig von den notify-Bedingungen
ThreadSynchronisation
Interaktion JVM und Speicher (1) - Definitionen
Hauptspeicher gemeinsam genutzt von allen Threads zur Speicherung von Variablen
(Klassenvariablen, Instanzenvariablen, Komponenten in Arrays)
Arbeitsspeicher jeder Thread hat eine Arbeitskopie „seiner“
Variablen
(Hauptspeicher hat die Master-Kopie)
Lock (Schloss) jedes Objekt hat sein eigenes Schloss
Threads konkurrieren um den Erwerb von
Locks
ThreadSynchronisation
Interaktion JVM und Speicher (2) - Definitionen
• Aktionen eines Threads
use
überträgt den Inhalt der Arbeitskopie einer Variablen des Threads an die Execution Engine des Threads assign
überträgt den Wert der Execution Engine des Threads in die Arbeitskopie des Threads load
überträgt einen Wert vom Hauptspeicher (Master-Kopie) durch eine vorgängige read Aktion in die Arbeitskopie des Threads store
überträgt den Inhalt der Arbeitskopie des Threads zum Hauptspeicher für eine spätere write AktionArbeits- speicher
Execution Engine
assignuse
Arbeits- speicher
Haupt- speicher
loadstore
ThreadSynchronisation
Interaktion JVM und Speicher (3) - Definitionen
• Aktionen eines Threads (Fortsetzung)
lock
Thread beansprucht ein bestimmtes Schloss(Beginn - Synchronisation zwischen Thread und Hauptspeicher)
unlock
Thread gibt ein bestimmtes Schloss frei(Ende - Synchronistion zwischen Thread und Hauptspeicher)
• Aktionen des Hauptspeichers – read, write
read
überträgt Inhalt der Master-Kopie einer Variablen in die Arbeitskopie des Threads für eine spätere load Aktion write
überträgt einen Wert vom Arbeitsspeicher des Threads vermittels einer store Aktion in die Master-Kopie einer Variablen imHauptspeicher
ThreadSynchronisation
Interaktion JVM und Speicher (4) - Regeln
Alle Aktionen sind atomar
• Thread-Aktionen use, assign, load, store, lock, unlock
• Speicher-Aktionen read, write, lock, unlock
Alle Aktionen
• irgendeines Threads
• eines Speichers für irgendeine Variable
• eines Speichers für irgendeinen Lock
sind total geordnet
Threads kommunizieren nicht direkt miteinander, sondern über den gemeinsamen Speicher
• lock oder unlock – gemeinsam ausgeführt von Thread und Hauptspeicher
• nach load (Thread) folgt immer read (Hauptspeicher)
• nach write (Hauptspeicher) folgt immer store (Thread)
• Alle Beziehungen sind transitiv
ThreadSynchronisation
Beispiel 1.1 – Elementares Tauschen
Klasse mit den Klassen-Variablen a und b und den Methoden hier und da
class Beispiel { int a = 1, b = 2;
void hier () { a = b;
}
void da () { b = a;
} }
write a -> read a, read b -> write b (ha = hb = da = db = ma = mb = 2) read a -> write a, write b ->read b (ha = hb = da = db = ma = mb = 1) ha, hb Arbeitskopien hier
da, db Arbeitskopien da
Masterkopien in Hauptspeicher
ThreadSynchronisation
Beispiel 1.2 – Synchronisiertes Swap
Klasse mit den Klassen-Variablen a und b und den Methoden hier und da
class SynBeispiel { int a = 1, b = 2;
synchronized void hier () { a = b;
}
synchronized void da () { b = a;
} }
unlock class SynBei unlock class SynBei
write a -> read a, read b -> write b (ha = ha = da = db = ma = mb = 2) read a -> write a, write b -> read b (ha = hb = da = db = ma = mb = 1) ha, hb Arbeitskopien hier
ha, hb Arbeitskopien da
Masterkopien im Hauptspeicher ma = 1 und mb = 2
ThreadSynchronisation
Beispiel 2.1 – Ungeordnetes Schreiben
Klasse mit den Klassen-Variablen a und b und den Methoden nach und von (die Methode liest beide Variablen und die andere schreibt beide Variablen)
class Beispiel { int a = 1, b = 2;
void nach() { a = 3;
b = 4;
}
void von()
System.out.println(„a=„+ a + „, b=„ +b);
} }
Ein Thread ruft nach und der andere Thread ruft von auf
nach Thread: assign für a assign für b
Weil keine Synchronisation: implementierungsabhängig, ob store nach Hauptspeicher (d.h. a = 1 oder 3 und b = 2 oder 4)
ThreadSynchronisation
Beispiel 2.2 – Ungeordnetes Schreiben (Fortsetzung)
Methode nach ist synchronisiert, aber Methode von ist nicht synchronisiert class Beispiel {
int a = 1, b = 2;
synchronized void nach() { a = 3;
b = 4;
}
void von()
System.out.println(„a=„+ a + „, b=„ +b);
} }
Ein Thread ruft nach und der andere Thread ruft von auf
nach Thread wird forciert store nach Hauptspeicher vor unlock am Ende auszuführen
to Thread wird use a und use b in dieser Reihenfolge ausführen
und daher load a und load b vom Hauptspeicher laden