NIO Best Practices - SelectableChannel and InterestOps
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.inte开发者_如何学GorestOps() | newOp)
Unregistering Interest:
- SelectionKey.cancel and SelectableChannel.register with new Ops
- VS. updating the existing SelectionKey like above
Are there any pros & cons?
Thanks
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.
I would update the existing interestOps using the or-operator as you suggest. I would be concerned about missing selections if I (temporarily) canceled the selection key.
Besides, cancel+reregister just seems more complicated than updating.
Unless you have an underlying logical reason for registering with new ops, I would suggest to always go with update.
精彩评论