This content has been marked as final. Show 9 replies
I have only been involved in NIO for a few weeks and initially had the same problem you had. EJP helped me and he is probably the best person to deal with this but I bet your problem comes from invoking this
outside of the 'select' thread since the interestOps(...) method blocks waiting for the lock that the 'select' thread holds (the read does no block, only the write). You can confirm this by using a debugger and putting a break point on the wakup() call; you will find it is not reached.
key.interestOps(key.interestOps() | SelectionKey.OP_READ);
I spent a lot of time researching this on the web but failed to find a satisfactory solution so came up with my own. My solution, most probably not standard, is to add the ability to inject functionality into the main select loop that runs before the rest of the loop. I embed the key.interestOps(key.interestOps() | SelectionKey.OP_READ); in the run() method of a Runnable and then add it to a list of Runnable to be executed (and then discarded) in the select loop. All I then have to do is to wakeup() the loop.
Obviously the functionality in the Runnable.run() method should do as little as is necessary.
I have managed to get rid of all threads associated with the select loop except where there is a need to interact with IO that cannot be run using NIO. In my case the primary one is interacting with Process objects created using ProcessBuilder.
Edited by: sabre150 on Jun 19, 2012 9:24 AM
my server code follows the well known pattern as follows;There are aspects of this that are not 'well-known' to me.
Why? You already know there is data, you can read it without blocking: why start another thread to do what you can do perfectly well right here?
The reading from the channel is delegated to a thread worker provided by the thread pool.Why?
It executes a code from a state object attached to the key. At the end of the read process I setup the READ interest back to true:Which will block due to the synchronization specified in the Javadoc for interestOps() and select(). Which is why you don't want to do this in a separate thread. NIO is all about a single thread. Do it that way. If you have zilliions of connections, or dozens of CPUs, run several selector threads and have them all handle their own connections. Don't even think about delegating I/O to other threads though, it is infinitely more trouble than it is worth.
if I put a debug statement right after the .select() call:
I see it each time the thread worker completes :
int count = selector.select(); logger.debug(String.format("%d keys selected", count));
It seems .weakup() properly interrupts the main thread. Even if I try to make a timeout on select just to ensure that the selector will make another cycle and will read the actual selectorKey flags it does not select the channel which is quite strange:
02:02:33,328 DEBUG Server:312 - 0 keys selected
int count = selector.select(1000);
16:41:11,636 INFO Server:310 - selected 0 16:41:12,637 INFO Server:310 - selected 0 16:41:13,638 INFO Server:310 - selected 0 16:41:14,639 INFO Server:310 - selected 0 16:41:15,640 INFO Server:310 - selected 0 16:41:16,641 INFO Server:310 - selected 0 16:41:17,642 INFO Server:310 - selected 0 16:41:18,643 INFO Server:310 - selected 0 16:41:19,644 INFO Server:310 - selected 0 16:41:20,645 INFO Server:310 - selected 0 16:41:21,646 INFO Server:310 - selected 0 16:41:22,647 INFO Server:310 - selected 0 16:41:23,648 INFO Server:310 - selected 0
I can read in main thread, it is not a problem. After that I can delegate the data to a worker thread for handling.
Reading in the main thread will be a bottle neck, right? All incoming to the server messages will get in one after another. Is this correct?
Yes it's correct but it would happen that way anyway. You are stuck with the order of the selected-key set returned by the Selector, and you are processing it sequentially. Nothing can change that. In my experience you are better off fiddling with the interestOps as little as possible.
Thank you EJP. I will move the reading to the main thread. This will definitely solve the problem. Honestly said if I comment the line :
all is working well and the client and the server exchange messages asynchronously. What makes me curious is that this code was working almost an year :) It seems switching to Java 7 has changes something. The pattern I mentioned is taken from the O'REALLY book Java NIO. Never-mind, thank you very much for answering my question.
key.interestOps(key.interestOps() & (~SelectionKey.OP_READ));
coderman wrote:It is always a possibility that there is some sort of regression because in Java7 the NIO API was revamped. But plenty of times when people post about "It was working in JavaX but it is not working in JavaY", they were actually doing it wrong all along and the real issue was that the JVM went along with it anyway.
It seems switching to Java 7 has changes something.
I did move the reading to the main thread. Now all is working fine. I hope this would not cause much troubles when the server reach 100k connections and 5% of them are simultaneously active. LOL
coderman wrote:If that happens please post back so we can all toast to your epic success, but until then I'll just say: it probably ain't gonna ever happen ;)
I hope this would not cause much troubles when the server reach 100k connections