InputStream in=channel.getInputStream(); |
This comes from a piece of code from an example of JSch , a good ssh client in java. A work collegue had the bad idea to remove the Thread.sleep call and was struggling with why it would randomly work.The way I would have done it is the following:
InputStream in=channel.getInputStream(); |
This has the advantage of being more readable and having less secret spices in it. In the first code, the call to available() is non blocking, meaning that without the Thread.sleep(), there will never be the time for the socket buffer to fill up. But is the first code more efficient or the second code?
I did a search on google to understand the interest of the first code. The only advantages I found in the first code are the possibility to interrupt the thread running the code and a finer grained control on timeouts.
There is a lengthy explanation by Doug Lea in his book "Concurrent Programming in Java". This book usually provides excellent explanations, and is a must read for anybody doing concurrent programming. But this time, about this subject, I did not find him that clear.
There is a more simple explanation in a course from San Diego State University (see last example)
A read() on an inputstream or reader blocks. Once a thread calls read() it will not respond to interrupt() (or much else) until the read is completed. This is a problem when a read could take a long time: reading from a socket or the keyboard. If the input is not forth coming, the read() could block forever.
Q. When will a Thread I/O blocked?A:When a thread executes a read() call on an InputStream, if no byte is available. The calling Thread blocks, in other words, stops executing until a byte is available or the Thread is interrupted.
Still I am wondering if the second code would not just go into IOException (socket timeout), on timeout (adjustable with Socket.setTimeout ) and release the Thread then. Do you have an idea when the first code could be better?
The first code makes no sense as is. If it were reading more than one input stream, it would make a little more sense, but not as much sense as using NIO.
ReplyDeleteYes, the first code is a bad example.
ReplyDeleteBut it's a problem that the java runtime doesn't throw an exception when a thread blocked on an IO primitive like read() is interrupted.
However it is possible to simulate this behavior by closing the socket on which the thread is blocked. (The limitation is that it is not always easy to get the socket reference.)
That's actually quite a neat trick. Sure nio is better, but sometimes one is stuck in pre-1.5 land.
ReplyDeleteThe 2nd code will block once the connection is interrupted (hardware unplugged, etc) while transmitting. Whereas the 1st code will recover.
ReplyDeleteI don't see why people say the first example is incorrect, or one should use NIO. The fact is listening on a SSH stream is a blocking event. NIO is useless here.
ReplyDeleteThe first example is correct, since one can inject a timeout into the loop and break, or look for end of input string like a prompt and break.
The second example it incorrect. While elegant, it will hang waiting on end of channel.
First code makes very good sense if you want implement the timeout functionality on inputStream.
ReplyDeleteI was using the jsch library, and while executing some remote commands application threads are BLOCKING indefinetly on inStream.read method.
Even after closing the sessions and channels the thread is not coming out from the read method.
I verified the thread dumps, netstats and confirming that all sessions and channels are closed, but my threaded never comes out from the read method.
After reading several articals i landed on this. The first approach mentioned here resolved the issue.
If any one intrested in the code please let me know.