NIO accept() loop, traditional thread for processing

J

John Hartnup

Hi folks,

I need to change a server so that it listens on multiple addresses and
ports, and behaves differently depending on which port is which. It
seems straightforward enough using nio, but I'd be most grateful if
someone would validate my approach.

I have followed standard tutorials to create ServerSocketChannels, set
them to non-blocking mode, and register them to a selector. Then I
loop around selector.select().

Here's the bit I want to validate:

while(stopped = false) {
selections = selector.select();
if(selections > 0) {
Set keys = selector.selectedKeys();
Iterator i = keys.iterator();
while(i.hasNext()) {
SelectionKey key = (SelectionKey) i.next();
ServerSocketChannel sch = (ServerSocketChannel) key.channel();
SocketChannel chan = sch.accept();
// chan.configureBlocking(true); // necessary? wise?
SessionHandler handler = new SessionHandler(chan.socket());
handler.start();
i.remove();
}
}
}

SessionHandler is a subclass of java.lang.Thread and has no NIO
related code in it. The toy server I've written in this way seems to
work, but do I need to worry about blocking when I'm handling serious
data? The existing code relies on blocking reads.

Also, is it safe to add a stop() method:
public void stop() {
stopped = true;
selector.wakeup();
}

?
 
E

Esmond Pitt

John Hartnup wrote:

SessionHandler is a subclass of java.lang.Thread and has no NIO
related code in it. The toy server I've written in this way seems to
work, but do I need to worry about blocking when I'm handling serious
data? The existing code relies on blocking reads.

Your code is OK and it will handle any number of server socket channels
in this single thread. But there's very little other benefit from using
NIO unless everything is non-blocking.
Also, is it safe to add a stop() method:
public void stop() {
stopped = true;
selector.wakeup();
}

Yes.
 
L

Lars Enderin

John Hartnup skrev:
Hi folks,

I need to change a server so that it listens on multiple addresses and
ports, and behaves differently depending on which port is which. It
seems straightforward enough using nio, but I'd be most grateful if
someone would validate my approach.

I have followed standard tutorials to create ServerSocketChannels, set
them to non-blocking mode, and register them to a selector. Then I
loop around selector.select().

Here's the bit I want to validate:

while(stopped = false) {

How can this loop ever be executed? (stopped = false) is always false.
Don't you mean while (!stopped) { ?
 
J

John Hartnup

John Hartnup skrev:






How can this loop ever be executed? (stopped = false) is always false.
Don't you mean while (!stopped) { ?


Actually (stopped = false) is always true, so the loop will never
exit.

I meant (stopped == false), or, as you correctly point out, (!
stopped). Thanks for catching that!
 
J

John Hartnup

Your code is OK and it will handle any number of server socket channels
in this single thread. But there's very little other benefit from using
NIO unless everything is non-blocking.

Thanks. The one important benefit I require is the ability to
simultaneously accept() on multiple SocketAddresses. So I'm happy :)
 
L

Lars Enderin

John Hartnup skrev:
Actually (stopped = false) is always true, so the loop will never
exit.

No, the java expression (stopped = false) has the value false. The
compiler should warn you about that.
I meant (stopped == false), or, as you correctly point out, (!
stopped). Thanks for catching that!

There is no need to test for boolean expression equality/unequality with
true or false, and there is an obvious risk of using = instead of ==.
 
J

John Hartnup

No, the java expression (stopped = false) has the value false. The
compiler should warn you about that.

My! I've been programming in Java for a good year without ever
noticing that, which at least demonstrates that I gained good habits
in my many years of C -- habitually typing "if(null == x)" instead of
"if(x == null)".

Thanks for the lesson. Incidentally, Eclipse does not warn about
this. The reason it slipped into the original post was that my test
version simply had "while(true)". The "stopped" variable was added to
the post to support a supplemental question. Thanks again.
 
L

Lars Enderin

John Hartnup skrev:
My! I've been programming in Java for a good year without ever
noticing that, which at least demonstrates that I gained good habits
in my many years of C -- habitually typing "if(null == x)" instead of
"if(x == null)".
It's even simpler to avoid the error in C:
(!x) is equivalent to (x == null), as any non-zero (non-null) value is
"true" (and 0 is false). It's a little obscure, though:
if (!strcmp(foo, bar)) { /* foo equals bar */ ... }
is counter-intuitive, at least to me.
 
D

Daniel Pitts

It's even simpler to avoid the error in C:
(!x) is equivalent to (x == null), as any non-zero (non-null) value is
"true" (and 0 is false). It's a little obscure, though:
if (!strcmp(foo, bar)) { /* foo equals bar */ ... }
is counter-intuitive, at least to me.

in c, strcmp(a,b) = 0 isn't valid, so you're not likely to need that
safety on that call :)
Part of me wishes java supported converting null/not null references
to boolean false/true primatives.

public void myProcess(Object a) {
if (!a) {
throw new NullPointerException("Cannot process nothing. Must
process something.");
}
doProcess(a);
}

I understand the arguments against it. perhaps a special "if" syntax:
if set(a) {
System.out.println("A is not null");
}
if unset(a) {
System.out.println("A is null");
}

And an associated trinary: a set? "A is not null" : "A is null";
 
M

Michael

Thanks. The one important benefit I require is the ability to
simultaneously accept() on multiple SocketAddresses. So I'm happy :)

Well, technically they won't be simultaneous because they're in a
single thread. You might do better to just have multiple server
threads. Then if you have multiple CPUs you'll actually get better
concurrency at the processing of multiple socket-accepts, and you'll
have the benefit that the processing of each accept won't block the
acceptance of the next. Having 100 such blocked threads is nothing..
Now if you want thousands of threads, then this is probably better.
I've seen Java stacks start to overflow at around 2,000 threads (with
default memory settings). Incidently, a good responsive server model
is to have a pool of worker threads able to handle all the different
types of jobs (think web servers).. Then you can use the NIO select or
have a different thread on each accept listener - they all just hand
off to the worker pool. In this way a single IO-blockage won't stall
the entire server, but at the same time, you can never overload the
server because it won't process more than k-jobs at a time. java 5
has some nice Executors.createXXXThreadPool(n) helpers for this.
 
E

Esmond Pitt

Michael said:
Well, technically they won't be simultaneous because they're in a
single thread. You might do better to just have multiple server
threads. Then if you have multiple CPUs you'll actually get better
concurrency at the processing of multiple socket-accepts, and you'll
have the benefit that the processing of each accept won't block the
acceptance of the next.

This is a bit futile really, as accepted connections are already queued
in the kernel, and as all the accepting thread has to do is register the
accepted channel with the selector. A well-written accept loop isn't a
bottleneck.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top