JavaParty Ausarbeitung für Version 1.07 Christian Lengauer Literatur: JavaParty Website Java Sprachreferenzen – p.1/20 Verteilte Programme in Java Natürliches Verteiltheitsmodell: Tasks: (Threads in) verschiedene(n) JVMs Daten: in einem nichtlokalen Speicher liegende Objekte SPMD ist ein Sonderfall! Zugriff auf verteilte Daten: remote method invocation (RMI) Speichermodell: lokaler Speicher unter Kontrolle der JVM lokaler Speicher allen lokalen Threads zugänglich (shared memory ) Synchronisation durch gegenseitigen Ausschluss (nur innerhalb einer JVM notwendig) Probleme mit der Speichersemantik (Google: Java Specification Request JSR-133 Cookbook) – p.2/20 Ansatz von JavaParty Verteilte Java-Programmierung so transparent wie möglich einzige Spracherweiterung: zusätzliches Objektattribut remote effizienteres RMI benutzt Java RMI Annahme: verläßliches Netz effizientere Serialisierung Speicherbereinigung mit Referenzzählern Objektplatzierung und -migration automatisch oder manuell Lokalitätsoptimierung durch automatische Migration (zum Benutzer oder anderswohin) durch Typüberprüfung (cloning mit Klassenspezialisierung) – p.3/20 Cloning zwei Aufrufe von bar mit Argumenten unterschiedlichen Typs gib jedem Aufruf eine eigene Kopie von bar dann kann jede für den konkreten Argumenttyp kompiliert werden – p.4/20 Syntax public remote class R { /** instance variable of remote class **/ public int x; /** instance method of remote class **/ public void foo() { ... } /** static variable of remote class **/ public static int y; /** static method of remote class **/ public static void bar() { ... } ... } – p.5/20 Zugriff auf entfernte Objekte und Klassen // create an instance of a remote class R f = new R; // access an instance variable of the // created remote object r.x = 42; // call its method foo() r.foo() // access a static member of a remote class R R.y = 13 // call a static method of the remote class R.bar() Klassentest eines Objektes mit instanceof wie lokal! – p.6/20 Objektmodell (Potenziell) entfernte Klassen: call by ref für entfernte Objekte als Parameter oder Resultate Instanzvariablen entfernter Objekte sind von überall zugreifbar die Klassenvariablen und -methoden entfernter Klassen existieren genau einmal (irgendwo) Lokale Klassen: ein lokales Objekt gehört zu der JVM, die es lädt, und ist nicht von anderswo sichtbar Übergabe von einem zu einem entfernten Objekt lokalen Objekt an ein anderes entferntes Objekt nur per Wert (wie beim Java RMI – egal, ob das Objekt wirklich entfernt ist) Laden und Initialisierung in jeder JVM individuell Zugriffe auf Klassenvariablen und -methoden einer lokalen Klasse beziehen sich immer auf das Klassenobjekt in der lokalen JVM – p.7/20 Aufrufe von Methoden entfernter Objekte Aufruf als lokal angenommen, wenn Aufruf an dasselbe entfernte Objekt: er erscheint in einer nicht-statischen Methode eines entfernten Objektes und er enthält keine explizite Referenz oder er enthält höchstens this- oder super-Referenzen Aufruf als entfernt angenommen, wenn möglicherweise Aufruf an ein anderes entferntes Objekt: als Bezugsobjekt ist der Name eines entfernten Objekt gegeben (selbst wenn dies das eigene Objekt ist!) bei statischen Methoden entfernter Klassen – p.8/20 Beispiel: lokale und entfernte Aufrufe lokal remote class R { void bar() { ... } entfernt remote class R { void bar() { ... } static void s_bar() { ... } void foo() { bar(); this.bar(); } void foo() { R r = this; r.bar(); s_bar(); R.s_bar(); r.s_bar(); } } } – p.9/20 Threads in JavaParty Umschlag für entfernte Fäden der Klasse java.lang.Thread: die neue Wrapper-Klasse jp.lang.RemoteThread Logischer Faden: folgen dem Kontrollfluss über verschiedene verteilte Objekte verknüpfen verschiedene physische Fäden Alternative bei Rückkehr in ein vorher verlassenes Objekt neuer Faden wird gebildet (Verklemmungen möglich!) einmal verlassener Faden wird wieder aufgenommen (transparenter Faden – vermeidet Verklemmungen) – p.10/20 Beispiel: logische Fäden Betrachte den folgenden Code: remote class A { B b; remote class B { A a; void foo() { b.bar(); } void bar() { a.foo2(); } } void foo2() { ... } } – p.11/20 Beispiel: logische Fäden ...Standard in Version 1.06... Problem, wenn foo und foo2 synchronisiert sind: Faden V kommt nicht an Objekt a ran! – p.12/20 Beispiel: transparenteFäden ...Standard in Version 1.07... Alles klar: Faden T hat a schon! – p.13/20 Synchronisation in Java: Objektmethoden int count; synchronized void bump() { count++; } ⇓ int count; void bump() { synchronized(this) { count++; } } – p.14/20 Synchronisation in Java: Klassenmethoden static int classCount; static synchronized void classBump() { classCount++; } ⇓ static int classCount; static void classBump() { try { synchronized(Class.forName("BumpTest")) { classCount++; } } catch (ClassNotFoundException e) { ... } } – p.15/20 Synchronisation in JavaParty entfernte Methoden: können Attribut synchronized tragen public remote class R { public synchronized void foo() { // A synchronized remote method } } Blöcke: können mit entferntem Objekt parametrisiert sein public void foo() { R remoteObject = ...; synchronized (remoteObject) { // A block synchronized // on a remote object } } – p.16/20 Tipps und Tricks Fadentransparenz schützt nicht vor Fehlverhalten! Lies Java-Literatur über Synchronisation, Fäden und Locks! Äußerste Vorsicht mit Monitoren (Problem: Aufrufhierarchien) Synchronisiere eher Methoden als Blöcke (Ausschluss auf ganzen Methodenrümpfen statt auf Teilen) Synchronisiere statische Methoden nur für entfernte Klassen (lokale Klassen werden dupliziert; jede Kopie hat ihre eigene Synchronisation) – p.17/20 Objektplatzierung Drei Möglichkeiten: Standard: zufällige Knotenauswahl pure Java-Syntax (plus remote) möglicherweise schlechte Objektlokalität Verteilungstaktiken mittels Verteilerklassen werden beim Programmstart vom Laufzeitsystem installiert kontrollieren bei jedem new die Objektplatzierung Anwendungsprogramme bleiben pur explizite Platzierung mit Tag @at (Bsp.: ein Objekt pro Knoten) import jp.lang.DistributedRuntime; public void foo() { int cnt = DistributedRuntime.getMachineCnt(); for (int n = 0; n < cnt; n++) { /** @at n */ R r = new R(); } } – p.18/20 Objektmigration Migrationsinitiierung: Direktive DistributedRuntime.migrate(obj,id) Migrationszeitpunkt unterliegt Einschränkungen: ein Objekt, auf das gerade zugegriffen wird, darf nicht migrieren Erklärung der Nichtmigrierbarkeit eines Objektes Interface jp.lang.Resident ermöglicht spezielle Optimierungen durch JavaParty – p.19/20 Viel Spaß... ...bei der Java-Party!!! – p.20/20