Hello!
We are currently working on a program here, that uses asynchronous events being sent over sockets to some C program.
The outgoing message is written on a BufferedWriter, flushed and then a new Waiter instance is opened, that will accept incoming messages. Afterwards, the Thread is put into wait() state. When a notify() is noticed, the returned value is taken and returned back to the calling method. The incoming message is read from an BufferedInputReader and gets a little bit of computation before the "right" Waiter Thread is selected (this works fine). Now, the incoming message is written into a variable and notifyAll() is called.
For a lot of times, this works perfectly, but once in a while, a InterruptedException is thrown and destroys just the whole application. From my -simple- logging statements, it became clear, that the Exception is thrown just before/after the Thread goes into wait() state. No notify() action has been possible before the Exception is being thrown.
The whole program does not have a interrupt(); or throw new InterruptedException(); in it. Also, no Swing, AWT or Concurrent classes are employed anywhere. Therefore, there is no -obvious- reason, why this Exception is being thrown.
Do you have any idea? ... here's the code:
static class Waiter {
Object response;
public synchronized Object getResponse() {
try {
while (response == null) {
wait();
}
} catch (InterruptedException ex) {
System.out.println("InterruptedException has just been thrown!");
ex.printStackTrace();
}
return response;
}
public synchronized void setResponse(Object response) {
System.out.println("setting response");
this.response = response;
System.out.println("done with setting response");
notifyAll();
System.out.println("done with notifyAll");
}
}
protected class ControlParseThread extends Thread {
boolean stopped = false;
public void run() {
try {
react();
} catch (SocketException ex) {
if (stopped) // we expected this exception
return;
else
throw new RuntimeException(ex);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public void stopListening() {
this.stopped = true;
}
}
public class MyClass(){
protected LinkedList<Waiter> waiters;
protected synchronized StringBuffer sendAndWaitForResponse(String s,String rest)
throws IOException {
ControlParseThread th = new ControlParseThread();
th.start();
Waiter w = new Waiter();
synchronized (waiters) {
output.write(s);
output.flush();
if (rest != null)
writeEscaped(rest);
waiters.addLast(w);
}
System.out.println(waiting for Response");
StringBuffer lst = (StringBuffer) w.getResponse();
return lst;
}
/** helper: implement the main background loop. */
protected void react() throws IOException {
while (true) {
StringBuffer lst = new StringBuffer();
while (true) {
if (line.equals(".")){
break;
} else {
data.append(input.readLine());
}
}
Waiter w;
System.out.println("react()1: " + lst.get(0));
synchronized (waiters) {
w = (Waiter) waiters.removeFirst();
}
System.out.println("react()2: " + lst.get(0));
w.setResponse(lst);
System.out.println("react()3: " + lst.get(0));
}
}
}
And here's a sample log (not everything, of course, but should give you an idea of the problem. First, the correct computation:
waiting for Response
react()1: MyClass$ReplyLine@6f9b8e
react()2: MyClass$ReplyLine@6f9b8e
setting response
done with setting response
done with notifyAll
react()3:
...and now the deficient run (part):
waiting for Response
InterruptedException has just been thrown!
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at MyClass$Waiter.getResponse(MyClass.java:42)
at MyClass.sendAndWaitForResponse(MyClass.java:200)
[...]
at java.lang.Thread.run(Unknown Source)
...a little further down the way...
java.lang.NullPointerException
at MyClass.sendAndWaitForResponse(MyClass.java:201)
[...]
at java.lang.Thread.run(Unknown Source)
react()1: MyClass$ReplyLine@149b290
react()2: MyClass$ReplyLine@149b290
setting response
done with setting response
done with notifyAll
react()3:
...for anonymity reasons, only the relevant stacktrace is printed here. But order has not been changed. The NullPointer does pose a problem, but this is due to the result not being set by react() into Waiter.setResponse(Object response){ ... }.
At a small setup, there a ~30 threads using these methods.
Thanks in advance for your help. Please do not hesitate for any further information needed. It will be provided as soon as possible.
Oh, yeah: we're using
C:\>java -version
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)
C:\>
or:
hans@debian:~$ java -version
java version "1.6.0_02"
Java(TM) SE Runtime Environment (build 1.6.0_02-b05)
Java HotSpot(TM) Client VM (build 1.6.0_02-b05, mixed mode, sharing)
hans@debian:~$
Thanks and I wish you an enjoyable day.
Bye,
Hans