Objektreferenz serialisieren

Hallo!

Ich möchte die Referenz auf ein Objekt und nicht das Objekt selbst serialisieren und über streams schreiben bzw. lesen. Gibt es da irgendeine Möglichkeit? Gibt es vielleicht ein Objekt, das nur die Referenz eines Objektes speichert und das Objekt über die Referenz wieder rekonstruieren kann und serialisierbar ist?

Florian

Hallo Florian,

Schau mal:
java.io.Externalizable

Gruss, Simon

Hallo!

Erstmal danke für die schnelle Antwort!

Schau mal:
java.io.Externalizable

Ich hab’ mir das angeguckt und sogar mal ein Sample programmiert, aber was soll mir das bringen? Ich will doch die Objektreferenz übertragen und damit hat das ja gar nix zu tun…

Mein konkretes Problem ist: Ich hab’ zwei Threads. Beide Threads sollen ein und dasselbe Objekt für eine Operation benutzen. Dieses Objekt ist NICHT serialisierbar. Einer der beiden Threads hat das Objekt und soll es an den anderen übertragen. Ich habe keine Möglichkeit das Objekt konventionell zu übertragen: Also mit irgendeiner Set - Funktion der Klasse des zweiten Threads zu übergeben. Also möchte ich die REFERENZ des Objektes mit Hilfe eines PipedOutputStream bzw. PipedInputStream zwischen den Threads übertragen. Ich will also die Objektreferenz schreiben, lesen und dann wieder auf das Objekt verweisen… wie geht das??? Hilfe!!!

Florian

Hallo,
Du brauchst ein Handle auf das referenzierte Objekt, daß unabhängig von der Laufzeitumgebung ist und persistent gemacht werden kann, also z.B. Serializable ist. Ist der Code der Klasse des ref. Objekts veränderbar ?

Gruss
Enno

Mein konkretes Problem ist: Ich hab’ zwei Threads. Beide
Threads sollen ein und dasselbe Objekt für eine Operation
benutzen. Dieses Objekt ist NICHT serialisierbar. Einer der
beiden Threads hat das Objekt und soll es an den anderen
übertragen. Ich habe keine Möglichkeit das Objekt
konventionell zu übertragen: Also mit irgendeiner Set -
Funktion der Klasse des zweiten Threads zu übergeben. Also
möchte ich die REFERENZ des Objektes mit Hilfe eines
PipedOutputStream bzw. PipedInputStream zwischen den Threads
übertragen. Ich will also die Objektreferenz schreiben, lesen
und dann wieder auf das Objekt verweisen…

Was hindert dich daran die Referenz „normal“ zu übergeben?

Ich glaub es wäre gut dein Problem genauer zu beschreiben, vielleicht finden sich andere, einfachere Lösungswege.

Ein statisches Objekt wäre z. B. eine Variante, damit bräuchtest du überhaupt keine Referenz übergeben.

Grüße, Robert

Hi!

Was hindert dich daran die Referenz „normal“ zu übergeben?

Die Ästhetik. Das Konzept meines Programmes basiert darauf das alle Kommunikation zwischen verschiedenen Threads, die im Programm eine besondere Bedeutung haben, über Streams abläuft (Piped streams um genau zu sein). Wenn ich dieses Paradigma aufbreche kann ich’s auch gleich lassen. Ich kann hier schlecht das komplette Konzept des Programms erklären - es ist ein sehr komplexes Distributed Computing - System. Wenn ich den Threads untereinander Zugriffe erlaube geht die ganze Logik flöten.
Die Threads laufen aber im selben Prozess. Deswegen müsste es rein technisch möglich sein eine Referenz zu übertragen.

Ich glaub es wäre gut dein Problem genauer zu beschreiben,
vielleicht finden sich andere, einfachere Lösungswege.

Also um es ganz genau zu sagen: Ich will, dass ein Input- und ein OutputStream, die von einem Thread erzeugt werden, einem anderen Thread zur Verfügung gestellt werden. Nun sind streams aber nicht serialisierbar. Also will ich nur die Referenz übertragen. Eine Übergabe der Referenzen mittels einer Methode steht wie gesagt nicht zur Diskussion. Auch irgendeine Trickserei mit statischen Variablen oder sonst was nicht (siehe unten).
Es ist wichtig für die Logik des Programms das die gesamte Kommunikation über die streams läuft, die einem Thread zur Verfügung stehen.

Ein statisches Objekt wäre z. B. eine Variante, damit
bräuchtest du überhaupt keine Referenz übergeben.

Daran hab’ ich auch schon gedacht aber das ist total hässlich :smile:.

Florian

Hallo,
Du brauchst ein Handle auf das referenzierte Objekt, daß
unabhängig von der Laufzeitumgebung ist und persistent gemacht
werden kann, also z.B. Serializable ist.

Ja genau, bis auf ein Detail: Die Laufzeitumgebung ist definitiv dieselbe. Es sind nur verschiedene Threads desselben Prozesses die diese Handles austauschen sollen.

Ist der Code der
Klasse des ref. Objekts veränderbar ?

Was meinst du mit veränderbar?
Um ein wichtiges Detail preiszugeben: Die Klasse des referenzierbaren Objekts enthält Streams, die natürlich erst zur Programmlaufzeit erstellt werden. Bekanntermaßen sind die Streams nicht serialisierbar.

Florian

Hallo

Was hindert dich daran die Referenz „normal“ zu übergeben?

Die Ästhetik. Das Konzept meines Programmes basiert darauf das
alle Kommunikation zwischen verschiedenen Threads, die im
Programm eine besondere Bedeutung haben, über Streams abläuft
(Piped streams um genau zu sein). Wenn ich dieses Paradigma
aufbreche kann ich’s auch gleich lassen. Ich kann hier
schlecht das komplette Konzept des Programms erklären - es ist
ein sehr komplexes Distributed Computing - System. Wenn ich
den Threads untereinander Zugriffe erlaube geht die ganze
Logik flöten.
Die Threads laufen aber im selben Prozess. Deswegen müsste es
rein technisch möglich sein eine Referenz zu übertragen.

Du solltest Dein Design überdenken! Ästhetik ist Geschmacksfrage, richtiges Design nicht.
Das ‚Paradigma‘ von Streams ist nunmal eine by value Semantik. Dies ist bei Interprozesskommunikation auch nicht anders sinnvoll, da eine Adresse in einem anderen Prozessraum keine Bedeutung hat.
Threads greifen auf den gleichen Prozessraum zu und erlauben eine by Reference Semantik. Dies ist natürlich gefährlicher und wird am besten durch ein Framework gekapselt (gibt es für Java auch OpenSource).
Deine Mischung hört sich nach Kopf durch die Wand an und würde in C/C++ auch gelingen, weil Du dort eine Adresse als Integer übertragen kannst und auf der anderen Seite des Streams wieder in eine Objektadresse casten kannst.
In Java ist dies gott sei Dank nicht möglich und bewart uns ein Gutteil vor schwer wartbaren Programmen, wie sie teils in C/C++ entstanden sind.
Wenn man wie ich auch in C/C++ viel programmiert hat, vermisst man anfangs einiges, aber die Einschränkung, das Java eben keine Pointer unterstützt, zwingt einen manchmal zum Nachdenken und führt dann hoffentlich zu einem besseren Design.

Hallo,
Dein Kernproblem scheint mir nichts mit serialisierbar oder nicht zu tun zu haben (innerhalb zweier Threads derselben VM lassen sich ordinäre Referenzen einfach so übergeben). Ziel scheint mir, daß die beiden Threads nicht voneinander „wissen“ sollen. Das könnte z.B. simpel über Callbacks oder Notification erfolgen, d.h. der „Streamkonsument“ registriert sich beim „Streamlieferanten“ und wird im Falle der Verfügbarkeit des Stream durch einen einfachen Methodenaufruf benachrichtigt.

Gruss
Enno

Hi!

Du solltest Dein Design überdenken! Ästhetik ist
Geschmacksfrage, richtiges Design nicht.
Das ‚Paradigma‘ von Streams ist nunmal eine by value Semantik.
Dies ist bei Interprozesskommunikation auch nicht anders
sinnvoll, da eine Adresse in einem anderen Prozessraum keine
Bedeutung hat.
Threads greifen auf den gleichen Prozessraum zu und erlauben
eine by Reference Semantik. Dies ist natürlich gefährlicher
und wird am besten durch ein Framework gekapselt (gibt es für
Java auch OpenSource).
Deine Mischung hört sich nach Kopf durch die Wand an und würde
in C/C++ auch gelingen, weil Du dort eine Adresse als Integer
übertragen kannst und auf der anderen Seite des Streams wieder
in eine Objektadresse casten kannst.
In Java ist dies gott sei Dank nicht möglich und bewart uns
ein Gutteil vor schwer wartbaren Programmen, wie sie teils in
C/C++ entstanden sind.
Wenn man wie ich auch in C/C++ viel programmiert hat, vermisst
man anfangs einiges, aber die Einschränkung, das Java eben
keine Pointer unterstützt, zwingt einen manchmal zum
Nachdenken und führt dann hoffentlich zu einem besseren
Design.

Unter Ästhetik verstehe ich nicht, ob der Quellcode cool aussieht. Unter der Ästehtik eines Systems fasse ich den Gesamteindruck zusammen, der sich ergibt, wenn man die Funktionsweise und das Zusammenspiel der einzelnen Komponenten betrachtet. Und in diesem Fall war es die Abstraktion von bestimmten Vorgängen innerhalb des Programms, die mich dazu bewogen, genau dieses Design zu wählen. Wie es jemand in einem anderen Posting bereits konkretisierte: Die Threads wissen nichts voneinander und sollen das auch nicht. Die Idee ist, dass jede Komponente des Systems seine Arbeit macht ohne irgendetwas darüber wissen zu müssen, wie der Rest des Systems funktioniert. Deswegen will ich eben nicht, dass jeder Thread, der irgendeine Aufgabe erfüllt, Objekte von jedem anderen Thread haschen muss, mit denen er zusammenarbeiten will. Die grundlegende Idee ist, dass es nur eine Kommunikationsverbindung nach außen gibt, die zu einem Verteiler führt, der die Kommunikation unter den einzelnen Komponenten regelt. So bekommt man eine hervorragend wartbare und modifizierbare Software weil man nämlich - wenn man eine Komponente verändert - keine andere verändern muss, weil sie niemals voneinander wissen mussten, um funktionieren zu können.
Also möchte ich, dass die Kommunikation mit jeder anderen Komponente über dasselbe Medium funktioniert um diese Abstraktion zu gewährleisten - dann spielt es nämlich keine Rolle mehr wo sich die andere Komponente befindet… egal ob auf demselben Rechner oder auf einem anderen Computer. Und Streams sind da eben die einzige Möglichkeite die universell funktioniert. Ich wollte nicht direkte Referenzierung implementieren wenn sich die andere Komponente auf dem gleichen Rechner befindet und dann noch einmal eine Stream-Variante wenn die Kommunikation über das Netzwerk erfolgt. Das bricht die Abstraktion auf. Also versuche ich die ganze Kommunikation mit Streams zu regeln. So jetzt hab’ ich dich genug vollgelabert :smile:.

Florian

Hallo Florian,

Deine Motivation ist durchaus verständlich, deine Anforderungen an Modularität und Abstraktion sind für verteilte Applikationen auch durchaus gängig, nur solltest du deinen Lösungsansatz überdenken.

Dazu zu deinem konkreten Fall:

Ich wollte nicht direkte Referenzierung
implementieren wenn sich die andere Komponente auf dem
gleichen Rechner befindet und dann noch einmal eine
Stream-Variante wenn die Kommunikation über das Netzwerk
erfolgt.

Das Problem, das du hast ist, dass du zwar die Kommunikation abstrahierst, aber nicht die Daten die du austauscht. Wenn du deine Komponenten in Zukunft trennst (unterschiedlicher Prozessraum), dann kannst du das zwar, weil dein Kommunikationskanal das unterstützt, funktionieren wird es aber trotzdem nicht, weil die Referenz die du überträgst ungültig wird wenn du sie in einen anderen Prozessraum überträgst.

D. h. du musst Daten übertragen die es beiden Threads unabhängig voneinander erlauben auf diesselbe Ressource zugreifen können.

Was das ist hängt jetzt wieder davon ab was hinter deinen Streams steht, wenns eine Datei ist könntest du z. B. einen Dateinamen übertragen. Allerdings musst du dann noch die Probleme beim konkurrierenden Zugriff auf die Datei lösen (z. B. über ein Lock-File).

Ein ganz anderer Lösungsansatz wäre es eine RPC-Variante zu implementieren, z. B. über Java RMI (Remote Method Invocation). Damit können Prozesse auf Objekte zugreifen die in einem anderen Prozessraum laufen. Da hättest du dann ein zentrales Objekt das den Zugriff auf die Ressource übernimmt und alle anderen Prozesse greifen über das Netzwerk auf dieses zentrale Objekt zu.

Was sich für dich eignet hängt von dem Anwendungsfall ab. Die RMI-Variante hängt halt an einer zentralen Stelle, wenn die ausfällt, dann gehen die anderen Prozesse auch nicht mehr (das würde sich über verteilte EJBs lösen lass, je nachdem was du tust ist das aber wahrscheinlich Overkill).

Falls du noch Fragen zu dem Thema hast, frag einfach. :smile:

Grüße, Robert

1 „Gefällt mir“

Hi!

Das Problem, das du hast ist, dass du zwar die Kommunikation
abstrahierst, aber nicht die Daten die du austauscht. Wenn du
deine Komponenten in Zukunft trennst (unterschiedlicher
Prozessraum), dann kannst du das zwar, weil dein
Kommunikationskanal das unterstützt, funktionieren wird es
aber trotzdem nicht, weil die Referenz die du überträgst
ungültig wird wenn du sie in einen anderen Prozessraum
überträgst.

Das ist vollkommen klar. Das ist natürlich ein wichtiger Punkt.

D. h. du musst Daten übertragen die es beiden Threads
unabhängig voneinander erlauben auf diesselbe Ressource
zugreifen können.

Ich will diese Referenzierungstechnik eigentlich nur prozessintern nur Initialisierung der (lokalen) Programmstruktur verwenden.

Was sich für dich eignet hängt von dem Anwendungsfall ab. Die
RMI-Variante hängt halt an einer zentralen Stelle, wenn die
ausfällt, dann gehen die anderen Prozesse auch nicht mehr (das
würde sich über verteilte EJBs lösen lass, je nachdem was du
tust ist das aber wahrscheinlich Overkill).

Ganz genau. Ich halte RMI für viel zu kompliziert - also für viel zu fehleranfällig - um es zu verwenden. Es handelt sich hier um eine Software, die von „einfachen“ Benutzern (d.h. nicht Java-Programmierern) genutzt werden soll. Und die werden wohl wenig Lust haben erstmal den RMI server zu konfigurieren…

Die einzige wirklich universell einsetzbare Methode, wäre, die Kommunikation generell über Sockets herzustellen - auch wenn nur lokale Threads miteinander reden sollen. Aber das halte ich für Overkill.

Florian

Ich will diese Referenzierungstechnik eigentlich nur
prozessintern nur Initialisierung der (lokalen)
Programmstruktur verwenden.

Dann verstehe ich aber ehrlich gesagt nicht, was da noch gegen das austauschen der Referenz auf herkömmlichem Weg spricht.

Bei der Architektur einer Anwendung soll man zwar schon einerseits Wert auf Flexibilität und Erweiterbarkeit legen, aber andererseits muss man wirklich auch schauen, dass man keine „vergoldete“ Lösung baut. Z. B. ein tolles, „schönes“ Konzept, das aber bei der Implementierung soviel Aufwand verursacht, dass du das nie wieder über die Vorteile des Konzepts reinholen kannst.

Und das man unterschiedliche Techniken für Kommunikation innerhalb eines Prozesses und zwischen verschiedenen Prozessen verwendet ist ganz normal. :smile:

Ganz genau. Ich halte RMI für viel zu kompliziert - also für
viel zu fehleranfällig - um es zu verwenden. Es handelt sich
hier um eine Software, die von „einfachen“ Benutzern (d.h.
nicht Java-Programmierern) genutzt werden soll. Und die werden
wohl wenig Lust haben erstmal den RMI server zu
konfigurieren…

Das lässt sich für den Benutzer relativ transparent machen, den RMI Server kann man z. B. auch in einen der Prozesse einbetten, der Benutzer muss sich dann gar nicht darum kümmern.

Die einzige wirklich universell einsetzbare Methode, wäre, die
Kommunikation generell über Sockets herzustellen - auch wenn
nur lokale Threads miteinander reden sollen. Aber das halte
ich für Overkill.

Für Verteilte Anwendungen gibt es schon genug Middleware-Technologien, also Sockets braucht da heutzutage keiner mehr. Als Beispiele zu nennen wäre da dezentrales Messaging (z. B. TIBCO Rendezvous, http://www.tibco.com) oder dezentrale Object Spaces (z. B. Corso http://www.tecco.at/en/index.html).

Das sind allerdings kostenpflichte Produkte und für dich wiederum Overkill. Eventuell gibts aber auch freie Produkte in dem Bereich, mir ist nur gerade nix bekannt. Aber wie gesagt, ich würde einfach RMI nehmen. :smile:

Grüße, Robert

Danke! o.w.t.
o.t.