Synchronisation in Java Studienprojekt Invisible Web Tang Zhihong
Synchronisation in Java Synchronisationsproblem Monitore Wait und notify PipedInputStream und PipedOutputStream Synchronisation von Collections
Synchronisationsproblem Nebenläufigkeit: zwei oder mehr Vorgänge gleichzeitig ausführen Sobald auf einem Rechner mehr als ein Prozess laüft, kann es zu Problemen Kommen. Z.B. wenn Zwei Prozesse gleichzeitig auf die selben Daten zugreifen, können Inkonsistenzen entstehen.
Synchronisationsproblem Beide Lesen : Unproblematisch Aber wenn einer liest und einer schreibt: Vorher oder nachher lesen? Oder beide Schreiben: Wer darf nachher schreiben Beispiel :Account Ein Kontostand wird von den Thread erhört undverringert.
Synchronisationsproblem class Account { String name; float amount; public Account(String name, float amount) { this.name = name; this.amount = amount; } public void deposit(float amt) { float tmp = amount; tmp += amt; try { Thread.sleep(1); } catch (InterruptedException e) { // ignore } amount = tmp; } public void withdraw(float amt) { float tmp = amount; tmp -= amt; try { Thread.sleep(1); } catch (InterruptedException e) { // ignore } amount = tmp; } public float getbalance() { return amount; } }
Synchronisationsproblem public class AccountTest { private static int NUM_OF_THREAD = 1000; static Thread[] threads = new Thread[NUM_OF_THREAD]; public static void main(string[] args) { final Account acc = new Account("John", 1000.0f); for (int i = 0; i< NUM_OF_THREAD; i++) { threads[i] = new Thread(new Runnable() { public void run() { acc.deposit(100.0f); acc.withdraw(100.0f); } } ); threads[i].start(); } for (int i=0; i<num_of_thread; i++) { try { threads[i].join(); } catch (InterruptedException e) { // ignore }} System.out.println("Finally, John's balance is:" + acc.getbalance());}}
Synchronisationsproblem Ergebnisse: Finally, John's balance is:6000.0 Finally, John's balance is:6400.0 Finally, John's balance is:6600.0 Finally, John's balance is:6500.0 Finally, John's balance is:7100.0 Ursache: unsynchronisiert gemeinsame Klassenvariable amount deposit und withdraw nicht atomar
Monitore Monitor-Konzept Monitor: Kapselung eines kritischen Bereichs mit Hilfe einer automatisch verwalteten Sperre kritischen Bereichs : eines Programmteils, der nur von jeweils einem Prozess zur Zeit durchlaufen werden darf
Monitore Schlüsselwort: synchronized synchronized auf eine Methode public synchronized void deposit(float amt) {Anweisungen} public synchronized void withdraw(float amt) {Anweisungen}
Monitore synchronized auf einen Block von Anweisungen einzelne Anweisungen können mit lock-objekt synchronisiert werden: Object lock= new Object(); in deposit: public void deposit(float amt) {synchronized(lock) {Anweisungen}} in withdraw: public void withdraw(float amt) {synchronized(lock) {Anweisungen}}
Monitore Es gibt ein Objekt lock, das sich die Methoden im kritischen Bereich(synchronized) teilen müssen, daher Synchronisation. alle Threads, die zur gleichen Zeit versuchen, einen kritischen Bereich eines locks zu betreten, werden solange blockiert, bis der Thread, der in seinem kritischen Bereich gerade abläuft, fertig ist.
wait und notify Potentielle Gefahr von Systemverklemmungen, sog.deadlocks weitere Synchronisationsprimitive: Methoden Wait() und notify()
wait und notify Beispiel: wenn amount >=0, Abbuchen (withdraw) von Konto. wenn amount<0, muss der Thread wihtdraw warten, bis Kontostand wieder positive ist. ABER: alle anderen synchronisierten Threads sind gesperrt das Programm ist in Deadlock
wait und notify Account mit DeadLock class Account{... synchronized void deposit(float amt) {...} synchronized void withdraw(float amt) { try{ while(amount<amt); // Warteschleife } catch(interruptedexception e){ return} amount -=amt;}... }
wait und notify Account ohne DeadLock class Account{... synchronized void deposit(float amt) {... notify(); } synchronized void withdraw(float amt) { try{ while(amount<amt) wait(); } catch(interruptedexception e){ return} amount -=amt;}... }
wait und notify Beispiel public class BSync { int totalthreads; int currentthreads; public BSync(int x) { totalthreads = x; currentthreads = 0;} public synchronized void waitforall() { currentthreads++; if(currentthreads < totalthreads) { try { wait(); } catch (Exception e) {..} } else { currentthreads = 0; notifyall(); } }}
wait und notify Wait()immer in Schleife aufrufen, in der man die Bedingung prüft, auf die der Thread warted Wenn Thread A aus wait() erwacht, betritt er den Monitor an der Wartestelle wieder. Falls Thread B, der notify() auslöste, noch im Monitor ist, muss A warten, bis B den Monitor verlassen hat, da nur ein Thread im Monitor möglich ist! wait() und notify() dürfen nur aus synchronisierten Methoden aufgerufen werden
wait und notify
PipedInputStream und PipedOutputStream mit Hilfe einer Pipe zu synchronisieren beiden Threads über einen ByteStream miteinander verbunden, der von einem Thread geschrieben und von dem anderen gelesen wird. Piping-Konzept : durch die Klassen PipedInputStream und PipedOutputStream realisiert
PipedInputStream und PipedOutputStream die gesamte Synchronisationsarbeit wird automatisch beim Aufruf der read- und write- Methoden erledigt Direkte Kommunikation mit PipeStream:
Synchronisation von Collections Die neuen Collections des JDK 1.2 nicht thread-sicher auf den Gebrauch des Schlüsselworts synchronized weitgehend verzichtet haben Methode: eine unsynchronisierte Collection in eine synchronisierte verwandeln
Synchronisation von Collections Static CollectionsynchronizedCollection(Collection c) static List synchronizedlist(list list) static Map synchronizedmap(map m) static Set synchronizedset(set s) static SortedMap synchronizedsortedmap(sortedmap m) static SortedSet synchronizedsortedset(sortedset s)