Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NIO Best Practices - SelectableChannel and InterestOps

Tags:

java

selector

nio

using java.nio one has to register interest in operations via the SelectableChannel:

SelectionKey = SelectableChannel.register(selector, interestInOpsBitmask)

Registering Interest:

  • overwriting the existing SelectionKey by executing SelectableChannel.register with new Ops
  • VS. updating the existing SelectionKey with key.interestOps(key.interestOps() | newOp)

Unregistering Interest:

  • SelectionKey.cancel and SelectableChannel.register with new Ops
  • VS. updating the existing SelectionKey like above

Are there any pros & cons?

Thanks

like image 414
hotzen Avatar asked May 21 '10 08:05

hotzen


People also ask

What is NIO Selector?

Last update: 2021-03-10. The Java NIO Selector is a component which can examine one or more Java NIO Channel instances, and determine which channels are ready for e.g. reading or writing. This way a single thread can manage multiple channels, and thus multiple network connections.

What is a selector thread?

A selector provides a mechanism for monitoring one or more NIO channels and recognizing when one or more become available for data transfer. This way, a single thread can be used for managing multiple channels, and thus multiple network connections.

How does NIO work in Java?

In NIO we work with channels and buffers. Data is always written from a buffer to a channel and read from a channel to a buffer. Selectors: Java NIO provides the concept of "selectors". It is an object that can be used for monitoring the multiple channels for events like data arrived, connection opened etc.

What are NIO threads?

nio is a non-blocking API for socket connections, which means you are not tight to the number of threads available. With this library, one thread can handle multiple connections at once.


1 Answers

If you always dispatch execution to a thread pool after select() return, you may wish to immediately cancel the key, since you loose the control over the time the Runnable will execute.

Ex.: If you perform the next select() before canceling the previous key (the thread is still waiting for execution), it will be valid yet, causing another thread to carry the already dispatched key. If one of these threads cancels the key, the other will get a CancelledKeyException besides introducing unexpected behavior.

Even if you cancel the key, a thread may register the same channel (update selection keys) before the channel become unregistered (due to your previous key.cancel()). What, again, will cause a CancelledKeyException.

To get rid of this trap, you may want to handle events always in the next loop:

while (true) { // true or something less risky
    //for each pendingTasks call
    pool.execute(task);
    Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
    while (iter.hasNext()) {
        SelectionKey key = iter.next();
        iter.remove();
        key.cancel();
        //store dispatch for the next while iteration
        pendingTasks.add(task); // do not execute tasks before next select()
    }
    selector.select(TIMEOUT); // or selectNow if there are 
                              //any pending events to handle.
}

Firt execution will, almost, never return keys, but the select() at the end of your loop MAY guarantee the channel of canceled key be unregistered (bear it's up to your impl) from selector.

However, if you are simply executing a task in the same thread you listen to your selector events, updating sounds easy and safer.

like image 72
paulosuzart Avatar answered Oct 12 '22 09:10

paulosuzart