PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [Java] "Singleton" pro Thread?


Ganon
2007-01-22, 18:42:51
Hi.

Die Klasse, welche bei mir alle Programmkonfigurationen enthält, ist bei mir ein Singleton, um diese von überall aufrufen zu können. Das klappt auch alles schön.

Jetzt habe ich noch eine Klasse, welche Texte aus einer XML-Datei ausliest, um die Texte dann abrufen zu können. Jedes Untermodul ist bei mir jedoch zwecks Parallelität ein extra Thread. Bisher holt jeder Thread seine Texte für sich, was jedoch das Problem verursacht das ich andauernd das Objekt mit übergeben müsste. Mach ich aus dem Teil ein Singleton würden die Unterprogramme sich die Texte gegenseitig überschreiben, da es "nur" eine HashMap ist.

Jetzt die Frage, was ich machen kann. Kann ich quasi ein "Singleton" pro Thread erstellen (ich weiß, wäre in dem Sinne kein Singleton), oder müsste ich die interne Datenstruktur anpassen, damit gemeinsamer Zugriff möglich ist?

Oder hat Java da schon was, was ich bisher übersehen habe?

Danke. :)

Wanginator
2007-01-29, 10:22:00
Ich bin mir nicht sicher ob ich dein Problem richtig verstanden habe, aber ein Singleton pro Thread wäre ja (wie du schon meintest) kein Singleton mehr, sondern einen normale Objektreferenz pro Thread. Also nehm ich an, man könnte die Referenz als Objektvariable pro Thread speichern oder eine globale HashMap erstellen, die von Thread auf dein "Singleton"-Objekt abbildet.

ethrandil
2007-01-29, 11:10:58
Ja prinzipiell ist sowas möglich.

Du könntest auch eine Klasse XMLThread von Thread ableiten, die das selber übernimmt (und dann auch nicht gegen andere Threads synchronisiert sein muss).
Ansonsten könntest du mit der Thread.getId()-Methode die Threads gegenüber einer anderen (statischen) Klasse identifizieren und in einer HashMap (oder sowas wie ConcurrentHashMap) speichern.

mfg
- eth

Monger
2007-01-29, 12:03:21
Das Singleton Pattern ist wohl das überbewerteste Pattern überhaupt. Versteif dich bitte nicht darauf!
Du brauchst es fast nie.

Ich bin nicht ganz sicher ob ich dich richtig verstehe, aber ich vermute, dass du ein Problem damit hast, dass du bestimmte Daten mindestens zwischen zwei Thread teilen möchtest (z.B. dem Hauptthread und einem Worker-Thread). Im Prinzip kannst du da beliebig die Objekte hin- und herrreferenzieren, du musst sie aber synchronisieren, damit zwei zugreifende Threads keinen Mist darauf produzieren.

Synchronisation ist ein riesiges Thema. Threads anlegen kann jeder, aber die dann anschließend vernünftig zu synchronisieren, ist die echte Herausforderung. Lies dir bei Sun die Tutorials zu dem Thema durch, sowas kann man hier nichtmal in zehn Zeilen abhandeln.

Abnaxos
2007-01-29, 12:10:54
Code, einfach so mal hingeschrieben (ungetestet):

public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> threadInstance =
new ThreadLocal<ThreadLocalSingleton>();

private ThreadLocalSingleton() {
}

public static ThreadLocalSingleton getInstance() {
ThreadLocalSingleton instance = threadInstance.get();
if ( instance == null ) {
instance = new ThreadLocalSingleton();
threadInstance.set(instance);
}
return instance;
}
}
(Edit: "static" nachgeführt)

Diesen Code produziert habend muss ich allerdings noch hinzufügen, dass ich Singletons im Allgemeinen für phöhse halte (kommt natürlich immer auch auf die Situation an). Zu oft ist es mir schon passiert, dass ich von einem vermeintlichen Singleton dann doch plötzlich zwei verschieden konfigurierte Instanzen gebraucht habe, und dann hat man den Dreck ... Also eher einfach die Referenz durchreichen oder, was ich bevorzuge, ein IoC-Framework verwenden, dass es erlaubt, Singletons anzulegen und zu konfigurieren, ohne das Singleton-Pattern anwenden zu müssen.

Ich bevorzuge hier HiveMind (mit einem eigenen Aufsatz darauf, der einige Dinge ergänzt, die mir in HiveMind fehlen). Mit HiveMind wäre jetzt dort gestanden:

<service-point id="MySingleton" interface="MyInterface" model="singleton">
<invoke-factory>
<construct class="MySingleton"/>
</invoke-factory>
</service-point>

Um das nun pro Thread zu haben, würde es genügen, stattdessen zu schreiben:

<service-point ... model="thread">
...
</service-point>

Ganon@work
2007-01-29, 15:51:08
Das Singleton Pattern ist wohl das überbewerteste Pattern überhaupt. Versteif dich bitte nicht darauf!
Du brauchst es fast nie.

Es geht darum das ich eine XML-Konfigurationsdatei ein mal einlese und diese dann am gesamten Programm abfragen kann. Dies trifft genauso auf die Texte zu, die überall angezeigt werden. Hier will ich nicht durch 3 Klassen eine Objektreferenz durchschleifen, nur für die Texte. Wie gesagt. Am besten die Klasse da holen, wo ich sie brauche. ;)

Da das jetzt schon ne Woche her ist, hab ich mich für die Variante mit der verschachtelten HashMap in einem Singleton entschieden. Aber umstellen kann ich es immer noch. ;)

Synchronisation ist ein riesiges Thema. Threads anlegen kann jeder, aber die dann anschließend vernünftig zu synchronisieren, ist die echte Herausforderung.

Jups, aber die Untermodule (in Threads) laufen soweit komplett für sich und müssen nicht auf die anderen Threads zugreifen, noch schreiben sie in die Singleton-Klassen irgendwas, was den anderen Thread interessieren könnte. Von daher dürfte sich da auch nichts blockieren.


@alle anderen

Danke. Ich werde es mal probieren, bzw. mal angucken. :)

tokugawa
2007-01-29, 16:27:59
Das Singleton Pattern ist wohl das überbewerteste Pattern überhaupt. Versteif dich bitte nicht darauf!
Du brauchst es fast nie.


Dem kann ich zwar zustimmen, aber es geht beim Singleton-Pattern auch oft nicht um's "brauchen" an sich, sondern darum, dass es eine elegante und schöne Möglichkeit dafür ist, auf etwas zuzugreifen das per Design nur einmal vorhanden sein darf.

Wenn man's negativ ausdrücken will, könnte man sagen es ist ein Pattern das Bequemlichkeit fördert (vor allem wenn die Alternative wäre, Referenzen/Pointer durchzuschleifen).

Natürlich kann man das Singleton-Pattern oft vermeiden - aber man will es ja deswegen benutzen weil es sehr komfortabel ist.

ethrandil
2007-01-29, 17:08:26
Wenn die HashMap ihre Methoden nicht atomar implementiert, kann es wohl auch mit dem Singleton zu einem Problem kommen.
Folgende Situation:

Thread A und Thread B wollen gleichzeitig das erste Mal ihr Datenobjekt haben. Dann kann es HashMap-intern Probleme geben. Denn es wird ja das erste mal beim Abrufen sehr wohl etwas in die HMap geschrieben.

Man kann die HMap natürlich auch im Vorhinein initialisieren - dann gibt es wirklich keine Probleme beim reinen Lesen.

mfg
- eth

Gast
2007-01-29, 20:10:51
Ich bin mir nicht sicher ob ich dein Problem richtig verstanden habe, aber ein Singleton pro Thread wäre ja (wie du schon meintest) kein Singleton mehr, sondern einen normale Objektreferenz pro Thread.öhm... was ist denn ein Singleton anderes als eine Objektreferenz pro Thread?
Ich dachte, Singleton bedeutet, es gibt nur eine einzige Instanz der Klasse, aber beliebig viele Referenzen auf diese Instanz?
So verstehe ich zumindest
http://de.wikipedia.org/wiki/Einzelstück_(Entwurfsmuster)#Implementierung_in_Java

Die Non-Singleton-Alternative wäre dann eine Instanz pro Thread.

Abnaxos
2007-01-30, 03:06:34
öhm... was ist denn ein Singleton anderes als eine Objektreferenz pro Thread?
Ich dachte, Singleton bedeutet, es gibt nur eine einzige Instanz der Klasse, aber beliebig viele Referenzen auf diese Instanz?
Du hast die Frage doch schon selber beantwortet: Ein Singleton ist ein Objekt, das im gesamten Programm (und damit natürlich auch über sämtliche Threads) einmalig ist. Mit Threads hat es erstmal garnichts zu tun, wann welcher Singleton wo und warum exisitert.

Im Zusammenhang mit Java kann man die obige Aussage relativieren, indem man die ClassLoader ins Spiel bringt. Das hätte jedoch weder mit Multithreading noch mit dem Topic etwas zu tun.

Monger
2007-01-30, 08:04:13
Dem kann ich zwar zustimmen, aber es geht beim Singleton-Pattern auch oft nicht um's "brauchen" an sich, sondern darum, dass es eine elegante und schöne Möglichkeit dafür ist, auf etwas zuzugreifen das per Design nur einmal vorhanden sein darf.

Und genau das ist eine unheimlich starke Bedingung. Wann macht es denn Sinn, Einmaligkeit zu fordern? Was, wenn der Benutzer mehrere Anwendungen parallel laufen lassen will? Was, wenn sich im nachhinein herausstellt, dass man seine Struktur doch öfters braucht?

In aller Regel ist das Singleton ein "Hack", um auf etwas global zugreifen zu können. Oft genug ist dann aber die gesamte Programmstruktur schräg und schief, und man sollte sich überlegen warum solche unschönen Maßnahmen überhaupt notwendig sind.

Wenn die HashMap ihre Methoden nicht atomar implementiert, kann es wohl auch mit dem Singleton zu einem Problem kommen.

Ab 1.4 oder so gibt es extra für diesen Fall synchronisierte Maps, und diverse andere synchronisierte Strukturen aus dem Collections-Framework. Die sollte man sich unbedingt ansehen, bevor man anfängt da selber sich irgendwas von Hand zu friemeln.

Gast
2007-01-30, 09:14:22
Ich kann Monger nur voll und ganz zustimmen. Anstatt die eigenen Anwendungs-Objekte Singleton zu machen würde ich eher auf ein ausgefeiltes Caching System zurückgreifen. Aus eigener Erfahrung kann das mit dem Singleton ganz böse ausarten, je größer die Anforderungen mit der Zeit werden.

Gast
2007-01-30, 11:39:04
Du hast die Frage doch schon selber beantwortet: habe ich nicht. Es sei denn, die Antwort lautet:
gar nichts, die Singleton-Lösung bedeutet, daß jeder Thread, der auf das Singleton zugreifen will, zumindest eine Objektreferenz auf das Singleton benötigt.
Wanginators These:

aber ein Singleton pro Thread wäre ja (wie du schon meintest) kein Singleton mehr, sondern einen normale Objektreferenz pro Thread.
wäre demnach falsch, da "ein Singleton pro Thread" hieße, daß es pro Thread nicht nur eine eigene Objektreferenz, sondern gleich ein eigenes Objekt gäbe.

Gast
2007-01-30, 12:06:01
Und genau das ist eine unheimlich starke Bedingung. Wann macht es denn Sinn, Einmaligkeit zu fordern? z.B. wenn eine Klasse einen Satz an Konfigurationseinstellungen kapselt, die im gesamten Programm einheitlich sein sollen. Gäbe es von so einer Klasse mehrere Instanzen, müßten ja jedes Mal, wenn eine davon verändert wird, die anderen darüber informiert werden um sich ebenfalls zu ändern.
Gleiches gilt, wenn das gesamte Programm nicht viel anderes tut, als ein bestimmtes Objekt zu manipulieren. Beispiel: bei einem 3D-Spiel macht es Sinn, wenn die darzustellende Szene als Objekt nur einmal vorhanden ist.

Was, wenn der Benutzer mehrere Anwendungen parallel laufen lassen will? die Einmaligkeit bezieht sich selbstverständlich auf eine einzige Anwendung.

Was, wenn sich im nachhinein herausstellt, dass man seine Struktur doch öfters braucht?dann muß er die Struktur des Programmes anpassen. Sollte aber auch nicht sooo großen Aufwand machen. Es sollte reichen, die Methode getInstance() durch Methoden wie createNewInstance(), getLatestInstance(), getInstanceById(int id) zu ersetzen.

Monger
2007-01-30, 12:57:40
z.B. wenn eine Klasse einen Satz an Konfigurationseinstellungen kapselt, die im gesamten Programm einheitlich sein sollen. Gäbe es von so einer Klasse mehrere Instanzen, müßten ja jedes Mal, wenn eine davon verändert wird, die anderen darüber informiert werden um sich ebenfalls zu ändern.

Dafür nutzt man dann gerne ein Factory Pattern, was dann hintendran entweder direkt auf die Festplatte zugreift (z.B. für irgendwelche Konfigurationsdaten), oder nochmal zwischenpuffert. Klar ist das im Endeffekt auch eine Art Singleton. Ich verdamme das Pattern ja auch nicht grundsätzlich, ich sag nur: es ist hoffnungslos overused. Man sollte nie bewusst ein Singleton implementieren, sondern einfach das tun was in der Situation sinnvoll ist.


die Einmaligkeit bezieht sich selbstverständlich auf eine einzige Anwendung.

Err... sicher?
Ich bin da nicht ganz so fit, aber wird denn für jedes Java Programm eine eigene Runtime geöffnet? Wenn nein, wurde die Klasse beim zweiten Start nämlich bereits geladen, und damit haben beide Programme den Zugriff auf das selbe Singleton.

EcHo
2007-01-30, 13:08:47
Err... sicher?
Ich bin da nicht ganz so fit, aber wird denn für jedes Java Programm eine eigene Runtime geöffnet?
Ja.

Abnaxos
2007-01-30, 13:51:34
Ja.
Nein.

In Tomcat beispielsweise laufen mehrere Applikationen in einer Runtime. Da ist das nicht so schlimm, da jede WebApp ihren eigenen ClassLoader hat, womit die Klassen mehrfach existieren, womit Singletons für jede Applikation einzeln existieren (es sei denn, die entsprechende Klasse befindet sich zufällig im System-Classpath, dann gibt es sie nur einmal für die gesamte JVM).

In JBoss kann es jedoch verheerend werden, da JBoss, wenn man es ihm nicht anders sagt, sich nicht an die J2EE-Classloading-Spezifikation hält, was im Zusammenhang mit Singletons zu lustigen Effekten führen kann.

€dit/€rgänzung: Es kann mit JBoss auch zu lustigen Effekten im Zusammenhang mit Singletons kommen, wenn man ihn so einstellt, dass er sich eben an die J2EE-Spezifikation hält, einfach in die andere Richtung. Bei meinem Aufsatz auf HiveMind (der u.A. HiveMind um eine vernünftige Classloading-Strategie erweitert) oder bei der Verwendung von OSGi kann ein und dieselbe Klasse in einer einzigen Applikation beliebig oft in derselben oder unterschiedlichen Versionen existieren.

EcHo
2007-01-30, 15:43:41
Naja,

der Tomcat ist ein Servlet- Container, also eine einzigste Application. Das darin Servlets im gleichen Context laufen, sollte klar sein.
Ich setzte WebApps nicht mit Anwendungen gleich, Microsoft bezeichnet sie auch sinnigerweise als Webparts.

Und der JBoss-Classloader ist wirklich ein Fall für sich. (Kennt jemand den JBoss 5 zufällig?).
Aber ein J2EE Server ist ja auch nichts anderes als ein Container für J2EE Anwendungen. Wer das entwickelt sollte sich halt mit der Spec auseinadersetzen.

Abnaxos
2007-01-30, 16:01:41
Naja,

der Tomcat ist ein Servlet- Container, also eine einzigste Application.
Ja, so kann man's natürlich auch sehen. Nicht selten laufen jedoch auf einem einzigen Tomcat mehrere Web-Applikationen, die gar nichts miteinander zu tun haben.

Ich wollte eigentlich vor allem nochmal herausstreichen, weshalb ich Singletons tunlichst vermeiden würde (und selber wenn immer möglich auch tue): Wegen vieler lustigen Effekte, sobald man mit etwas schlaueren Classloading-Strategien arbeitet (besonders OSGi), weil man häufig später eben doch mehrere Instanzen braucht und dann ein Problem hat und schlussendlich, weil ich Verfechter von IoC (Inversion of Control) bin und daher das Singleton-Pattern für ein Anti-Pattern halte.

EcHo
2007-01-30, 18:53:51
Ja, so kann man's natürlich auch sehen. Nicht selten laufen jedoch auf einem einzigen Tomcat mehrere Web-Applikationen, die gar nichts miteinander zu tun haben.

Ich wollte eigentlich vor allem nochmal herausstreichen, weshalb ich Singletons tunlichst vermeiden würde (und selber wenn immer möglich auch tue): Wegen vieler lustigen Effekte, sobald man mit etwas schlaueren Classloading-Strategien arbeitet (besonders OSGi), weil man häufig später eben doch mehrere Instanzen braucht und dann ein Problem hat und schlussendlich, weil ich Verfechter von IoC (Inversion of Control) bin und daher das Singleton-Pattern für ein Anti-Pattern halte.

Gut, dass kann ich so unterschreiben. Beim Singleton muss man wissen, ob man es braucht, machmal kommt man nicht drum herum.