I had to write an application which for short can hook into a network communication and forwards the stuff received to the intended receiver. For the interested, the protocol was JDWP, the Java debugger protocol. This is a two way communication and an asynchronous protocol. Since the structure of the protocol is similar in either direction the application centered around having one component which can forward the communication at both sides of the channel. I realized this with some kind of queue where the queue read and write was realized with two different threads to not block the asynchronous communication. One thread was reading from the queue and writing the contents to the OutputStream and one was reading the InputStream and writen to the queue. So I ended up with five threads when the application was connected, two for the communication to the clients side, two for the communication to the server side, and one for doing the “beef”. When running standalone, the application was connected via Input- and OutputStreams which where obtained from sockets.
Then I wanted to run that stuff within another application and didn’t want to have the overhead of connecting via a socket within the same application. So I connected internally via PipedOutputStream and PipedInputStream. No problem so far. Of course I had to implement the caller of that application as well and my journey began. The protocol goes for a handshake first which differs completely from the structure of the rest of the protocol (which in my opinion is a bad design). As well, my use case implied, that the return handshake could be not transmitted at all, or incompletely. To safeguard this, I thought that it was a good idea to carry out the handshake in a separate thread, join it for a given timeout and report error if the thread did not return within that time. That worked pretty well until I started to change the coding such that subsequent communication would not follow immediately after the handshake. Almost exactly two seconds after the handshake completed, the reading thread on the pipe went away with the exception that the pipe was broken. WTF!? I nowhere had a timeout of two seconds. I debugged into it and the first strange thing I saw when looking at the PipedInputStream that it has two Thread fields: readSide and writeSide. And strangely, the writeSide was holding the thread which did the handshake. Soon after that I realized, that PipedInputStream.read() checks if the writing thread is still alive and throws an Exception after two seconds waiting. And, really, the JavaDoc of PipedInputStream#read() states:
If a thread was providing data bytes to the connected piped output stream, but the thread is no longer alive, then an
Sigh :-(. Lesson learned: read JavaDoc of overridden methods. I changed my coding such that the handshake was carried out in the caller thread and I started a watchdog thread to interrupt after the given timeout.