NIO最佳实践 - SelectableChannel和InterestOps

时间:2010-05-21 08:02:08

标签: java selector nio

使用java.nio,必须通过SelectableChannel注册对操作的兴趣:

SelectionKey = SelectableChannel.register(selector, interestInOpsBitmask)

注册兴趣:

  • 通过使用新Ops执行SelectableChannel.register
  • 覆盖现有的SelectionKey
  • VS。使用key.interestOps(key.interestOps()| newOp)更新现有的SelectionKey

取消注册兴趣:

  • SelectionKey.cancel和SelectableChannel.register with new Ops
  • VS。像上面那样更新现有的SelectionKey

有没有专业人士和缺点

由于

2 个答案:

答案 0 :(得分:3)

我会按照您的建议使用or-operator更新现有的interestOps。如果我(暂时)取消选择键,我会担心缺少选择。

此外,取消+重新注册似乎比更新更复杂。

除非您有注册新操作的基本逻辑原因,否则我建议您始终使用更新。

答案 1 :(得分:3)

如果在select()返回后总是将执行调度到线程池,您可能希望立即取消该键,因为您在执行Runnable时会失去控制权。

例如:如果在取消上一个键之前执行下一个select()(线程仍在等待执行),它将有效,导致另一个线程携带已经调度的键。如果其中一个线程取消了密钥,另一个线程将获得CancelledKeyException,除了引入意外行为。

即使你取消了密钥,线程也可以在频道取消注册之前注册相同的频道(更新选择键)(由于你之前的key.cancel())。又是什么, 将导致 CancelledKeyException

要摆脱这个陷阱,您可能希望始终在下一个循环中处理事件:

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执行几乎不会返回键,但是循环结束时的select() MAY 可以保证取消键的通道从选择器中取消注册(由你的impl决定) 。

但是,如果您只是在同一个线程中执行任务,那么您可以听取选择器事件,更新声音更容易,更安全。