PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Verständnisproblem mit Threadsynchronisation



Technaton
23-08-2005, 19:08
Grüße euch!

Ich hab da ein kleines Problem, den Einsatz von .wait() bzw. notify() in Verbindung mit sychronized() zu verstehen.

Folgende beiden Klassen:



public class SomeWriter extends Thread
{
public String name = "";
public SomeWriter instance = new SomeWriter();

/* ... ne menge Zeugs ... */
public void run()
{
/* Tut Dinge, liest von Sockets, usw */
synchronized(name) {
name = zipentry.getName();
name.notify();
}
}
}



public class SomeReader extends Thread
{
String s;

public void run()
{
while(!interrupted()) {
synchronized(instanceOfSomeWriter.name) {
try {
instanceOfSomeWriter.name.wait();
s = instanceOfSomeWriter.name;
} catch (Exception e) { /* Exceptionhandling */ }
}
}
}
}

Gedacht ist, daß "SomeWriter" in unregelmäßigen Abständen einen Dateinamen in der Variable "name" ablegt. Wenn das getan ist, soll per "notify()" der wartende "SomeReader" benachrichtigt werden, der die Variable ausliest (und irgendwas damit tut), um dann wieder zurückzukehren und zu warten, bis erneut "notify()" aufgerufen wird. Soweit die Theorie. In der Praxis allerdings erhalte ich an der Stelle, an der ich notify(); aufrufe, eine IllegalMonitorStateException -- warum? Die einzigen Threads, die auf die Variable zugreifen, sind die aus "SomeReader" und "SomeWriter", und wenn die APIs nicht lügen, löst wait(); die Sperrung auf das Objekt -- also sollte der Monitor in dem Moment, in dem ich notify(); aufrufe, auch dem entsprechenden Thread gehören, oder?

Ich danke demjenigen, der mich dem Verständnis näher bringt. :)

Gruß,
Techl

peschmae
23-08-2005, 20:01
Du rufst notify() innerhalb des synchronizes-Blockes auf. Ich denke schon das ist in sich ein Wiederspruch - denn synchronized garantiert dir ja exklusiven Zugriff auf die Variable - und jetzt *während* du den hast sagst du einem anderen Thread er dürfe jetzt darauf zugreifen (was er ja nicht darf).

Scheint ich liege falsch mit meiner Vermutung und dein Code sollte korrekt sein. Das was du geschrieben hast allerdings nicht ganz 100%ig. notify() löst die Sperre nicht - es sagt dem anderen Thread nur "jetzt kannst du dann gleich" - d.h. das wait() wird aufgelöst - aber der muss dann ja trotzdem warten bis der erste Thread den synchronized() block verlassen hat um seinerseits synchronized-zugriff zu haben.

MfG Peschmä

Technaton
23-08-2005, 20:32
notify() löst die Sperre nicht - es sagt dem anderen Thread nur "jetzt kannst du dann gleich" - d.h. das wait() wird aufgelöst - aber der muss dann ja trotzdem warten bis der erste Thread den synchronized() block verlassen hat um seinerseits synchronized-zugriff zu haben.
Richtig. Meines Erachtens allerdings sollte das keine weiteren Probleme nach sich ziehen, schließlich verläßt der Thread die den synchronized()-Block wieder, hat dem 2. Thread "Bescheid gegeben", der dann seinerseits macht, was auch immer er tun soll. Würde ich Fehler im zweiten (im lesenden) Thread kriegen, wäre das auch in Ordnung für mich; aber ich kriege sie im ersten, und das verwirrt mich so.

peschmae
23-08-2005, 21:12
Wie gesagt - mir auch ein Rätsel. Schon mal eine alternative JVM (oder auch eine andere aka neuere Version von Sun) versucht?

MfG Peschmä

Technaton
23-08-2005, 22:01
Es muß am Code liegen. Ich habe mit 1.4.2 und 1.5 getestet, sowie mit einer Opensource-Implementierung. Immer IllegalMonitorStateException. Das Seltsame ist, daß es im Javabuch (javabuch.de) genau so, in der Konfiguration anscheinend funktioniert. Argl.

EDIT: Mit einem Vector geht's?! Wo ist denn der Unterschied zwischen String und Vector, beides sind doch Klassen und keine Primitive? :confused:

EDIT2: Gelöst. Anscheinend is s = "Bla"; gleichbedeutend mit s = new String("bla"); und das ein neue Objekt ist logischerweise nicht im Monitor. Ich habs mit einem Vector, einem StringBuffer und einer Hashtable ausprobiert, wenn ich sozusagen intern hinzufüge/entferne, bleibt alles beim alten, die Threads laufen und ich kriege keine Exception. Sachen gibt's :o

peschmae
24-08-2005, 09:14
Ach so, ist ja eigentlich ganz logisch wenn man dran denkt :D

MfG Peschmä

anda_skoa
24-08-2005, 11:12
String in Java ist nicht mutable, also nicht veränderbar.
Darum ist eine Zuweisung immer ein Erzeugung eines neuen Objekts.

Du könntest ja ansich auch auf den Writer synchronizen.

Ciao,
_