![]() |
| | Themen-Optionen |
| | Nach oben #1 |
| Gast
Beiträge: n/a
|
Hi leute. Nettes Forum!! Na dann poste ich doch gerade mal eine Frage: Ich habe eine Klasse geschrieben, wellche von aussen her gesehen wie ein Stack funktioniert (also man kann Objekte hinein "pushen" und wieder heraus "popen"). Die Objekte, welche im Stack abgelegt werden, sollen dann über das Netzwerk verschickt werden, und die Objekte, welche aus dem Netzwerk kommen, sollen dann über die Methode pop() abgeholt werden können. Ich hoffe, ihr kapiert in etwa, was ich gemacht habe. Nun zu meinem Problem: Ich wollte die Klasse so gut wie möglich Thread-Save machen, also dass keine Fehler auftreten bei mehrernen Threads die darauf zugreifen. Jedoch funktioniert das nicht richtig, irgend etwas erzeugt einen deat-lock.. Kann sich bitte jemand die Klasse ansehen und verbesserungsvorschläge posten? Besten Dank schon im Voraus. Code: public class StackSerializer {
ObjectInputStream m_ois;
ObjectOutputStream m_oos;
Vector m_inputStack;
Vector m_outputStack;
boolean m_read = true;
boolean m_write = true;
Thread m_inputThread;
Thread m_outputThread;
public StackSerializer(InputStream is, OutputStream os)
throws Exception {
m_oos = new ObjectOutputStream(os);
m_ois = new ObjectInputStream(is);
m_inputStack = new Vector();
m_outputStack = new Vector();
m_inputThread = new Thread() {
public void run() {
while (m_read) {
try {
insert(m_ois.readObject());
System.out.println("read object");
} catch (Exception ex) {
insert(ex);
m_read = false;
}
}
}
};
m_outputThread = new Thread() {
public void run() {
while (m_write) {
try {
m_oos.writeObject(remove());
System.out.println("wrote object");
} catch (Exception ex) {
insert(ex);
m_write = false;
}
}
}
};
m_inputThread.start();
m_outputThread.start();
}
public void stop() {
m_inputThread.interrupt();
m_outputThread.interrupt();
m_read = false;
m_write = false;
}
private synchronized void insert(Object o) {
m_inputStack.add(0,o);
}
private synchronized Object remove() {
if (m_outputStack.isEmpty()) {
try {
wait();
} catch (InterruptedException iex) {}
}
return m_outputStack.remove(m_outputStack.size()-1);
}
public synchronized Object pop() {
while (m_inputStack.isEmpty()) {
try {
wait();
} catch (InterruptedException iex) {}
}
return m_inputStack.remove(m_inputStack.size()-1);
}
public synchronized void push(Object o) {
m_outputStack.add(0,o);
notify();
}
}
Greets |
|
| | Nach oben #2 |
| Neuer Benutzer Registriert seit: 27.05.2004
Beiträge: 25
|
Hast mich gerade auf den zwei Themen erwischt, die ich höchstens am Rand kenne; Doch: Was ist genau die Fehlermeldung? (normalerweise gibts da ja so Zeilennummern...) Wär unter Umständen noch so hilfreich... mfG Bischi |
| | |
| | Nach oben #3 |
| Erfahrener Benutzer Registriert seit: 29.05.2004
Beiträge: 228
|
uiuiui, tatsächlich *ggg* Deadlock heisst es gibt keine Fehlermeldung und das ganze bleibt stehen weil z.B. zwei Threads jeweils auf das Beenden des anderen warten oder so. Zuerst mal noch ein OT-Hinweis: Du verwendest Vector - ab Java 1.2 sollte man bevorzugt ArrayLists (oder das entsprechende List-Interface) benutzen. Vector ist dort nur noch eine Kompatibilitätsklasse. (Wenn du allerdings Java 1.1 Kompatibilität willst ist das durchaus ok Scheint mir in Ordnung zu sein - naja, das heisst natürlich nix. Das Thread-Debugging schwierig ist wissen seit einigen Jahren auch die Hurd-Entwickler Kannst du mal ein bisschen Debugging Ausgaben einfügen versuchen (so println) um zu gucken wo die Threads sind wenn der Fehler auftritt und so? MfG Peschmä
__________________ Amazon.de | The Java Trap | Freie Software | Freie Software vs. Open Source | GNU Classpath | GCJ | SableVM "We should forget about small efficiencies, say about 97% of the time: Premature optimization is the root of all evil." - Donald Knuth |
| | |
| | Nach oben #4 | |
| Chefkoch-Mod Registriert seit: 30.05.2004
Beiträge: 433
| Zitat:
__________________ Denk mal darüber nach... Lars ACHTUNG: wenn ich von Klassen spreche, könnte ich auch deren Instanzen meinen. www.linuxforen.de +++ www.macuser.de +++ www.mrunix.de +++ www.lmprojects.de | |
| | |
| | Nach oben #5 | |
| Neuer Benutzer Registriert seit: 27.05.2004
Beiträge: 25
| Zitat:
mfG Bischi | |
| | |
| | Nach oben #8 |
| Gast
Beiträge: n/a
|
Der Fehler war, dass ich das wait und das notify auf die Klasse und nicht auf das zu sperrende objekt angewendet habe. Und auch dass ich die ganze Methode synchronisiert hab, anstatt nur das verwendete Objekt. Code:
import java.util.Vector;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.io.ObjectOutputStream;
public class StackSerializer {
ObjectInputStream m_ois;
ObjectOutputStream m_oos;
Vector m_inputStack;
Vector m_outputStack;
boolean m_read = true;
boolean m_write = true;
Thread m_inputThread;
Thread m_outputThread;
public StackSerializer(InputStream is, OutputStream os)
throws Exception {
m_oos = new ObjectOutputStream(os);
m_ois = new ObjectInputStream(is);
m_inputStack = new Vector();
m_outputStack = new Vector();
m_inputThread = new Thread() {
public void run() {
while (m_read) {
try {
insert(m_ois.readObject());
} catch (Exception ex) {
insert(ex);
m_read = false;
}
}
}
};
m_outputThread = new Thread() {
public void run() {
while (m_write) {
try {
m_oos.writeObject(remove());
} catch (Exception ex) {
insert(ex);
m_write = false;
}
}
}
};
m_inputThread.start();
m_outputThread.start();
}
public void stop() {
m_inputThread.interrupt();
m_outputThread.interrupt();
m_read = false;
m_write = false;
}
private void insert(Object o) {
synchronized(m_inputStack) {
m_inputStack.add(0,o);
m_inputStack.notifyAll();
}
}
private Object remove() {
synchronized(m_outputStack) {
if (m_outputStack.isEmpty()) {
try {
m_outputStack.wait();
} catch (InterruptedException iex) {}
}
return m_outputStack.remove(m_outputStack.size()-1);
}
}
public Object pop() {
synchronized (m_inputStack) {
while (m_inputStack.isEmpty()) {
try {
m_inputStack.wait();
} catch (InterruptedException iex) {}
}
return m_inputStack.remove(m_inputStack.size()-1);
}
}
public void push(Object o) {
synchronized(m_outputStack) {
m_outputStack.add(0,o);
m_outputStack.notifyAll();
}
}
}
|
|
| | Nach oben #10 |
| Gast
Beiträge: n/a
|
ja, da hat sich alles gegenseitig gesperrt, oder fehlermeldungen in der art von: java.lang.IllegalMonitorStateException: current thread not owner ausgespuckt. Aber ich bin froh, dass es jetzt funktioniert. Das wird der Grundbaustein der Server/Client Verbindung für mein Online-Game, und so kann ich Objekte hin und her schicken, ohne mich mit der Verbindung abzuquälen.. |
|
| | Nach oben #11 | |
| Gast
Beiträge: n/a
| Zitat:
Dazu bleibt mir dann nur noch anzumerken dass ich der Meinung bin, in einer Multi Thread Umgebung sollte man doch lieber Vektor verwenden. Der ist nämlich von Haus aus Thread-save. Wenn man doch eine Liste nehmen möchte bietet sich die Möglichkeit an eine Service-Funktion der Klasse Collections zu verwenden, um Zugriffe auf diese durch einen Wrapper synchronisieren zu lassen: http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collections.html#synchronizedList(java.util.List) [/OT} Cheers, makii | |
|
| | Nach oben #12 | ||
| Gast
Beiträge: n/a
| Zitat:
Es ist richtig, dass die neuen Collection Klassen (darunter ArrayList und HashMap) gegenüber den alten (darunter Vector und Hashtable) bevorzugt werden sollen. Dafür gibt es hauptsächlich zwei Gründe: 1. die neuen Klassen verwenden Iteratoren statt Enumerationen und sind über diese auch während einer Iteration manipulierbar (z.B. Iterator.remove) 2. die neuen Klassen sind nicht mehr thread-safe und daher im allgemeinen performanter Wenn man eine multi-threaded Anwendung schreibt, gibt es zwar mit den alten thread-safe Klassen bzw. den Collections.synchronized* Wrappern eine scheinbar einfache Möglichkeit die Anwendung selbst thread-safe zu machen, dies ist jedoch ausser in sehr einfachen Applikationen ein Irrtum und verführt den Programmierer zu dem falschen Glauben sich selbst nicht mehr um korrekte Synchronisierung kümmern zu müssen. Im allgemeinen müssen neben dem reinen Collection Zugriff auch noch weitere Aktionen synchronisiert werden. Benützt man nun synchronisierte Collection Klassen, so bedeutet dies oft, dass in einem bereits synchronisierten Codeteil eine synchronisierte Collection Methode aufgerufen wird, also zwei ineinandergeschachtelte Locks angefordert werden, wo doch eigentlich bereits das äussere Lock ausreichen würde. Mit dem allgemeinen Hinweis synchronisierte Collections in multi-threaded Applikationen zu verwenden, wird also darüberhinaus auch Performance verschenkt. cu | ||
|
![]() |
| Lesezeichen |
| Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1) | |
| Themen-Optionen | |
| |
Ähnliche Themen | ||||
| Thema | Autor | Forum | Antworten | Letzter Beitrag |
| Connection zu MSSQL | la-finest | Allgemeine Java-Programmierung | 2 | 09.08.2006 09:22 |
| Layout Manager? | Java17 | Desktop-Applikationen und Grafik | 18 | 01.03.2005 22:36 |
| Connection Conn richtig weitergeben? | ghost | Allgemeine Java-Programmierung | 32 | 12.02.2005 12:57 |
| Dieselbe Connection aus mehreren Prozessen nutzen? | Densi | Datenbanken | 1 | 29.10.2004 05:38 |
| [Klassen] Collections | bluelight | Allgemeine Java-Programmierung | 5 | 24.08.2004 16:39 |