Java.nio loading CPU

I am writing a server app to be able to handle multiple connections (in excess of 100) and I found the Java.nio package to be very useful in doing this.

However I have a problem. When there is at least one connection made to the server, the server's CPU becomes heavily loaded due to thewhile loop in which Selector.select() gets called. The problem is that select() returns a set of keys even if not a single byte was received by any of the SocketChannels registered to to the Selector. So mywhile loop just carries on running many times a second irrespective of whether any of the SocketChannels have received data or not, which they won't in normal operation due to the asynchronous nature of my app (it sends and receives data over cellular phone networks)

The relevant code is below:

this.selector.select();

while (this.opened)

{

Set<SelectionKey> selectedKeys = this.selector.selectedKeys();

Iterator<SelectionKey> it = selectedKeys.iterator();

while (it.hasNext())

{

SelectionKey key = it.next();

if (key.isAcceptable())

{

//handle a socket accept

}

if (key.isReadable())

{

//handle a socket read

}

if (key.isWritable())

{

//handle a socket write

}

it.remove();

}

this.selector.select();

}

this.selector is just theSelector which belongs to the class in which this code was implemented andthis.opened is just a boolean that will eventually be changed to false by another thread to indicate that the server has shutdown.

Before reading further: please note that this code works and the server handles client requests properly. The issue, is that the CPU is being used inefficiently andnot that the code doesn't work.

The problem is thatthis.selector.select() returns keys whoseready sets indicate that the keys are readable even if their associated SocketChannels have read zero bytes. So this loop just gets called repeatedly which is pointless for 99% of the time due to the infrequency of messages being passed between the client and server (remember: slow cellular phone networks). This also loads the CPU of the server heavily even if there is only 1 socket connection from a client.

So what can be done to prevent this? Is there a way of making theselect() method block until actual data has been read by a SocketChannel?

[3025 byte] By [hooloovoo13a] at [2007-11-27 1:52:52]
# 1
You should only register a channel for OP_WRITE when you have something to write to it. OP_WRITE is almost always true - it just means there is room in the send buffer.See http://forum.java.sun.com/thread.jspa?threadID=459338 for a pretty complete discussion.
ejpa at 2007-7-12 1:22:18 > top of Java-index,Core,Core APIs...
# 2

Thanks ejp for the very fast reply. I did exactly as you suggested and everything worked fine.

The tricky part was realising that when the interestOps of a SelectionKey (which is registered to a Selector) are changed from being unwritable to being writable, a Selector.wakeup() had to be called to stop the Selector.select() method from blocking. This is really weird behaviour as one would expect the select() method to return as soon as any of the Selector's SelectionKeys become writable, without having to call the wakeup() method.

hooloovoo13a at 2007-7-12 1:22:18 > top of Java-index,Core,Core APIs...
# 3

It does return when any of the keys becomes writable, but when you change the keys or interest sets while it's blocking it is already selecting in the kernel on the old keys and interest ops so it doesn't know about the new ones. That's why you have to wake it up. If you step through what happens next you'll find that it loops right around into another select() which then returns immediately.

ejpa at 2007-7-12 1:22:18 > top of Java-index,Core,Core APIs...