Überblick Collections Übersicht Package: java.util Gemeinsame Schnittstelle: Collection Datenstrukturen Java Collections & Maps Threads Synchronisation Koordinierung Menge Schnittstelle: Set Implementierungen: HashSet, TreeSet, ... Liste Schnittstelle: List Implementierungen: LinkedList, ArrayList, Vector, ... Warteschlange Schnittstelle: Queue Implementierungen: PriorityQueue, ArrayBlockingQueue, ... Tutorial: MW-Übung (WS10/11) Java – Collections & Maps 3–1 http://download.oracle.com/javase/tutorial/collections/index.html MW-Übung (WS10/11) Java – Collections & Maps Generische Datenstrukturen Traversieren von Datenstrukturen Beispiel Iterator (java.util.Iterator) Deklaration mittels generischem Datentyp (hier: E) 3–2 Methoden public interface List<E> extends Collection<E> {[...]} Instanziierung: E durch zu verwaltenden Datentyp ersetzen, z. B. String Collection<String> list = new LinkedList<String>(); hasNext() Überprüfung auf letztes Element next() Voranschreiten zum nächsten Element remove() Entfernen des aktuellen Elements Beispiel Vorteile Implementierung der Datenstruktur kann Datentyp-unabhängig erfolgen Typsicherheit bei Verwendung der Datenstruktur // Liste erzeugen und mit Elementen fuellen List < String > list = [...]; // Liste durchlaufen Iterator < String > iter = list . iterator (); while ( iter . hasNext ()) { String s = iter . next (); System . out . println ( s ); } Einschränkung des Datentyps Keine Einschränkung Collection<?> c; Einschränkung auf (Unter-)Klasse bzw. Schnittstelle Erweiterte Iteratoren verfügbar, z. B. java.util.ListIterator Collection<? extends Serializable> c; MW-Übung (WS10/11) Java – Collections & Maps 3–3 MW-Übung (WS10/11) Java – Collections & Maps 3–4 Traversieren von Datenstrukturen Maps For-Each-Schleife Bemerkungen Allgemeine Schnittstelle für Datenstrukturen zur Verwaltung von Schlüssel-Wert-Paaren Eigenschaften Anwendbar für alle Datenstrukturen, welche die Schnittstelle java.lang.Iterable<E> implementieren, sowie Arrays Rein lesender Zugriff auf die Datenstruktur Maximal ein Wert pro Schlüssel (→ keine Duplikate) Interner Aufbau bestimmt durch gewählte Implementierung (→ Nicht dazu geeignet, um Elemente in ein Array einzufügen) Beispiele HashMap TreeMap ... // Liste erzeugen und mit Elementen fuellen List < String > list = [...]; Beispiel // Liste durchlaufen for ( String s : list ) { System . out . println ( s ); } Map < String , Integer > telBook = new HashMap < String , Integer >(); telBook . put (" Alice " , 123456789); telBook . put (" Bob " , 987654321); [...] String [] array = { " A " , " B " , " C " }; // Array durchlaufen for ( String s : array ) { System . out . println ( s ); } MW-Übung (WS10/11) Integer aliceNumber = telBook . get (" Alice "); System . out . println (" Alice ’ s number : " + aliceNumber ); Java – Collections & Maps Algorithmen-Bibliothek java.util.Map<K,V> 3–5 java.util.Collections MW-Übung (WS10/11) Java – Collections & Maps 3–6 Überblick Verfügbare Algorithmen (Beispiele) Maximums- (max()) bzw. Minimumsbestimmung (min()) Sortieren (sort()) Überprüfung auf Existenz gemeinsamer Elemente (disjoint()) Erzeugung zufälliger Permutationen (shuffle()) Beispiel Implementierung Integer [] values = { 1 , 2 , 3 , 4 , 5 , 6 }; List < Integer > list = new ArrayList < Integer >( values . length ); Collections . addAll ( list , values ); Java Collections & Maps Threads Synchronisation Koordinierung System . out . println (" Before : " + list ); Collections . shuffle ( list ); System . out . println (" After : " + list ); Ausgabe eines Testlaufs Before : [1 , 2 , 3 , 4 , 5 , 6] After : [4 , 2 , 1 , 6 , 5 , 3] MW-Übung (WS10/11) Java – Collections & Maps 3–7 MW-Übung (WS10/11) Java – Threads 3–8 Was ist ein Thread? Erzeugung von Threads in Java Aktivitätsträger mit eigenem Ausführungskontext Variante 1: Unterklasse von java.lang.Thread Instruktionszähler Register Stack java.lang.Thread Vorgehensweise 1. Unterklasse von java.lang.Thread erstellen 2. run()-Methode überschreiben 3. Instanz der neuen Klasse erzeugen 4. An dieser Instanz die start()-Methode aufrufen Alle Threads laufen im gleichen Adressbereich Arbeit auf lokalen Variablen Kommunikation mit anderen Threads Beispiel Vorteile Ausführen paralleler Algorithmen auf einem Multiprozessorrechner Durch das Warten auf langsame Geräte (z. B. Netzwerk, Benutzer) wird nicht das gesamte Programm blockiert Nachteile ThreadTest test = new ThreadTest (); test . start (); Komplexe Semantik Fehlersuche schwierig MW-Übung (WS10/11) Java – Threads Erzeugung von Threads in Java class ThreadTest extends Thread { public void run () { System . out . println (" Test "); } } 3–9 java.lang.Runnable MW-Übung (WS10/11) Java – Threads Pausieren von Threads 3 – 10 sleep(), yield() Variante 2: Implementieren von java.lang.Runnable Vorgehensweise 1. Die run()-Methode der Runnable-Schnittstelle implementieren 2. Objekt der neuen Klasse erzeugen, das Runnable implementiert 3. Instanz von Thread erzeugen, dem Konstruktor dabei das Runnable-Objekt mitgeben 4. Am neuen Thread-Objekt die start()-Methode aufrufen Beispiel class RunnableTest implements Runnable { public void run () { System . out . println (" Test "); } } Java – Threads Mittels sleep()-Methoden static void sleep ( long millis ); static void sleep ( long millis , int nanos ); Legt den aktuellen Thread für millis Millisekunden (und nanos Nanosekunden) ,,schlafen” Achtung: Es ist nicht garantiert, dass der Thread exakt nach der angegebenen Zeit wieder aufwacht Ausführung auf unbestimmte Zeit aussetzen Mittels yield()-Methode static void yield(); Gibt die Ausführung zugunsten anderer Threads auf Keine Informationen über die Dauer der Pause RunnableTest test = new RunnableTest (); Thread thread = new Thread ( test ); thread . start (); MW-Übung (WS10/11) Ausführung für einen bestimmten Zeitraum aussetzen 3 – 11 MW-Übung (WS10/11) Java – Threads 3 – 12 Beenden von Threads return, interrupt() Regulär join() Mittels join()-Methode return aus der run()-Methode Ende der run()-Methode public void join() throws InterruptedException; Beispiel Abbruch nach expliziter Anweisung Aufruf der interrupt()-Methode MyWorker worker = new MyWorker (); // implementiert Runnable Thread workerThread = new Thread ( worker ); workerThread . start (); public void interrupt(); Wird (normalerweise) von außen aufgerufen Führt zu [...] einer InterruptedException, falls sich der Thread gerade in einer unterbrechbaren blockierenden Operation befindet einer ClosedByInterruptException, falls sich der Thread gerade in einer unterbrechbaren IO-Operation befindet dem Setzen einer Interrupt-Status-Variable, die mit isInterrupted() abgefragt werden kann, sonst. MW-Übung (WS10/11) Auf das Beenden von Threads warten Java – Threads 3 – 13 Veraltete Methoden try { workerThread . join (); worker . printResult (); } catch ( I n t e r r u p t e d E x c e p t i o n ie ) { // U n t e r b r e c h u n g s b e h a n d l u n g fuer join () } MW-Übung (WS10/11) Java – Threads 3 – 14 Thread-Zustände in Java BLOCKED/ WAITING/ TIMED_WAITING Als ,,deprecated” markierte Thread-Methoden NEW stop(): Thread-Ausführung stoppen destroy(): Thread löschen (ohne Aufräumen) suspend(): Thread-Ausführung anhalten resume(): Thread-Ausführung fortsetzen start() ... Warten auf IO Warten auf ein Lock sleep() Gründe IO bereit Lock verfügbar Zeit abgelaufen RUNNABLE stop() gibt alle Locks frei, die der Thread gerade hält → kann zu Inkonsistenzen führen destroy() und suspend() geben keine Locks frei yield() run() beendet Weitere Informationen “Java Thread Primitive Deprecation” http://download.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html MW-Übung (WS10/11) Java – Threads TERMINATED 3 – 15 MW-Übung (WS10/11) Java – Threads 3 – 16 Korrektheit nebenläufiger Programme Hauptaugenmerk liegt meist auf zwei Prinzipien Safety ,,Es passiert niemals etwas Schlechtes” Beispiele: ∗ Korrekte Berechnungen ∗ Korrekte (Zwischen-)Zustände ∗ Korrekte Ergebnisse ∗ ... Java Collections & Maps Threads Synchronisation Koordinierung Liveness ,,Es passiert überhaupt irgendetwas” Beispiele: ∗ Keine Deadlocks ∗ Stetiger Programm-Fortschritt ∗ ... Maßnahmen Synchronisation Koordinierung MW-Übung (WS10/11) Java – Synchronisation 3 – 17 MW-Übung (WS10/11) Java – Synchronisation Synchronisationsbedarf: Beispiel Probleme mit Multithreading: Beispiel public class Adder implements Runnable { public int a = 0; Ergebnis einiger Durchläufe: 1732744, 1378075, 1506836 public void run () { for ( int i = 0; i < 1000000; i ++) { a = a + 1; } } Was passiert, wenn a = a + 1 ausgeführt wird? public static void main ( String [] args ) throws Exception { Adder value = new Adder (); Thread t1 = new Thread ( value ); Thread t2 = new Thread ( value ); Mögliche Verzahnung, wenn zwei Threads beteiligt sind 0. a = 0; LOAD a into Register ADD 1 to Register STORE Register into a t1 . start (); t2 . start (); t1 . join (); t2 . join (); System . out . println (" Expected a = 2000000 , " + " but a = " + value . a ); } 1. T1-load: a = 0, Reg1 = 0 2. T2-load: a = 0, Reg2 = 0 3. T1-add: a = 0, Reg1 = 1 4. T1-store: a = 1, Reg1 = 1 5. T2-add: a = 1, Reg2 = 1 6. T2-store: a = 1, Reg2 = 1 → Die drei Operationen müssen atomar ausgeführt werden! } MW-Übung (WS10/11) 3 – 18 Java – Synchronisation 3 – 19 MW-Übung (WS10/11) Java – Synchronisation 3 – 20 Synchronisation in Java Das Schlüsselwort synchronized Übersicht Schutz von kritischen Abschnitten per synchronized-Block public void foo () { [...] // unkritische Operationen synchronized ( < Sperrobjekt >) { [...] // zu schuetzender Code ( krit . Abschnitt ) } [...] // unkritische Operationen } Grundprinzip Vor Betreten eines kritischen Abschnitts muss ein Thread ein Sperrobjekt anfordern Beim Verlassen des kritischen Abschnitts wird das Sperrobjekt wieder freigegeben Ein Sperrobjekt wird zu jedem Zeitpunkt von nur maximal einem Thread gehalten Ausweitung eines synchronized-Blocks auf die komplette Methode Beachte In Java kann jedes Objekt als Sperrobjekt dienen Ein Thread kann das selbe Sperrobjekt mehrfach halten (rekursive Sperre) synchronized public void bar () { [...] // zu schuetzender Code ( kritischer Abschnitt ) } Verbesserung für Beispiel synchronized ( this ) { a = a + 1; } MW-Übung (WS10/11) Java – Synchronisation Das Schlüsselwort synchronized 3 – 21 Nachteile MW-Übung (WS10/11) Java – Synchronisation 3 – 22 Wann muss synchronisiert werden? Atomare Aufrufe erforderlich 1. Der Aufruf einer (komplexen) Methode muss atomar erfolgen Anforderung (lock()) und Freigabe (unlock()) des Sperrobjekts sind nur im Java-Byte-Code sichtbar nicht trennbar (→ Vorteil: kein lock() ohne unlock()) Keine Timeouts beim Warten auf ein Sperrobjekt möglich Eine Methode enthält mehrere Operationen, die auf einem konsistenten Zustand arbeiten müssen Beispiele: - ,,a = a + 1” - Listen-Operationen (add(), remove(),...) 2. Zusammenhängende Methodenaufrufe müssen atomar erfolgen Keine alternativen Semantiken (z. B. zur Implementierung von Fairness) definierbar Methodenfolge muss auf einem konsistenten Zustand arbeiten Beispiel: List list = new LinkedList (); [...] int l as tO b je ct In d ex = list . size () - 1; Object lastObject = list . get ( la st Ob j ec tI nde x ); → Lösung: Alternative Synchronisationsvarianten (siehe später) Beachte: Code, der zu jedem Zeitpunkt nur von einem einzigen Thread ausgeführt wird, muss nicht synchronisiert werden! MW-Übung (WS10/11) Java – Synchronisation 3 – 23 MW-Übung (WS10/11) Java – Synchronisation 3 – 24 Synchronisierte Datenstrukturen java.util.Collections Die Klasse java.util.Collections Statische Wrapper-Methoden für java.util.Collection-Objekte Synchronisation kompletter Datenstrukturen Java Collections & Maps Threads Synchronisation Koordinierung Methoden static <T > List <T > s y n c hr o n i z ed Li st ( List <T > list ); static <K ,V > Map <K ,V > s yn chr on iz e dM ap ( Map <K ,V > m ); static <T > Set <T > syn c hr oniz e dS et ( Set <T > s ); [...] Beispiel List < String > list = new LinkedList < String >(); List < String > syncList = Collections . s yn c hronizedList ( list ); Beachte Synchronisiert alle Zugriffe auf eine Datenstruktur Löst Fall 1, jedoch nicht Fall 2 (siehe vorherige Folie) MW-Übung (WS10/11) Java – Synchronisation 3 – 25 Koordinierung MW-Übung (WS10/11) Java – Koordinierung 3 – 26 Koordinierungsbedarf: Das ,,Philosophen-Problem” Erkenntnisse Das Leben eines Philosophen beschränkt sich auf 2 Tätigkeiten: Denken und Essen (abwechselnd) Zum Essen benötigt man Messer und Gabel Synchronisation alleine nicht ausreichend Jeder Thread ,,lebt in seiner eigenen Welt” Threads haben keine Möglichkeit sich abzustimmen Experiment 4 Philosophen werden an einem runden Tisch platziert Zwischen 2 Philosophen liegt jeweils ein Messer oder eine Gabel Messer und Gabel können nicht gleichzeitig genommen werden Da nicht ausreichend Besteck für alle vorhanden ist, legt jeder Philosoph sein Besteck nach dem Essen wieder zurück Koordinierung unterstützt Verwaltung von gemeinsam genutzten Betriebsmitteln Rollenverteilung (z. B. Produzent/Konsument) Gemeinsame Behandlung von Problemsituationen ... Problem, falls (zum Beispiel) alle Philosophen zuerst das rechte und danach erst das linke Besteckteil nehmen wollen: Deadlock → Koordinierung notwendig MW-Übung (WS10/11) Java – Koordinierung 3 – 27 MW-Übung (WS10/11) Java – Koordinierung 3 – 28 Koordinierung in Java Übersicht Beispiel Variablen Grundprinzip Ein Thread wartet darauf, dass eine Bedingung wahr wird oder ein Ereignis eintritt Der Thread wird mittels einer Synchronisationsvariable benachrichtigt Beachte Object syncObject = new Object (); // Synchronisations - Variable boolean condition = false ; // Bedingung Auf Erfüllung der Bedingung wartender Thread synchronized ( syncObject ) { while (! condition ) { syncObject . wait (); } } Jedes Java-Objekt kann als Synchronisationsvariable dienen Um andere Threads über eine Synchronisationsvariable zu benachrichtigen, muss sich ein Thread innerhalb eines synchronized-Blocks dieser Variable befinden Bedingung erfüllender Thread Methoden synchronized ( syncObject ) { condition = true ; syncObject . notify (); } wait(): auf eine Benachrichtigung warten notify(): Benachrichtigung an einen wartenden Thread senden notifyAll(): Benachrichtigung an alle wartenden Thread senden MW-Übung (WS10/11) Koordinierung in Java Java – Koordinierung Explizite Locks 3 – 29 java.util.concurrent.locks.Lock MW-Übung (WS10/11) Java – Koordinierung Bedingungsvariablen 3 – 30 java.util.concurrent.locks.Condition Allgemeine Schnittstelle java.util.concurrent.locks.Lock Lock anfordern Schnittstelle: java.util.concurrent.locks.Condition void lock (); void loc kIn ter rup t i b l y () throws I n t e r r u p t e d E x c e p t i o n ; boolean tryLock (); boolean tryLock ( long time , TimeUnit unit ) throws I n t e r r u p t e d E x c e p t i o n ; Auf Signal (= Erfüllung der Bedingung) warten void await () throws I n t e r r u p t e d E x c e p t i o n ; // vgl . wait () void a w a i t U n i n t e r r u p t i b l y (); boolean await ( long time , TimeUnit unit ) throws I n t e r r u p t e d E x c e p t i o n ; boolean awaitUntil ( Date deadline ) throws I n t e r r u p t e d E x c e p t i o n ; Lock freigeben void unlock(); Signalisieren Condition-Variable für dieses Lock erzeugen void signal (); // analog zu notify () void signalAll (); // analog zu notifyAll () Condition newCondition(); Implementierung: java.util.concurrent.locks.ReentrantLock Beachte Lock lock = new ReentrantLock (); lock . lock (); [...] lock . unlock (); MW-Übung (WS10/11) Java – Koordinierung Ein Thread der await*() oder signal*() aufruft muss das zugehörige Lock halten (vgl. wait() und notify*() innerhalb synchronized-Block) 3 – 31 MW-Übung (WS10/11) Java – Koordinierung 3 – 32 Semaphoren java.util.concurrent.Semaphore Konstruktoren Semaphore ( int permits ); Semaphore ( int permits , boolean fair ); Semaphore belegen (= herunter zählen) acquire ([ int permits ]) throws I n t e r r u p t e d E x c e p t i o n ; a c q u i r e U n i n t e r r u p t i b l y ([ int permits ]); tryAcquire ([ int permits , ] [ long timeout ]); Semaphore freigeben (= herauf zählen) release([int permits]); Beispiel Semaphore s = new Semaphore (1); s . a c q u i r e U n i n t e r r u p t i b l y (); [...] s . release (); MW-Übung (WS10/11) Java – Koordinierung 3 – 33