我的Java NIO选择器是使用select()实现的,所以它会阻塞,直到出现以下任何一个:
由此,我对select()返回0 的情况做了一些假设:
ResultSetselectedKeys(),可以继续下一个循环迭代,select()再次调用但是,我遇到了select()返回0的情况,尽管有一个就绪通道.按预期selectedKeys()返回a Set为1 SelectionKey.
即使是几次调用select()也始终会返回0,直到处理完通道并SelectionKey删除它.这种情况基本上以无限循环结束,因为select()不阻止但总是立即返回0.
简化代码:
Selector selector = Selector.open();
SocketChannel channel;
for (...) { // for each node
// Create and connect channels...
...
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ, someRelatedObject);
}
int ready;
Set<SelectionKey> readyKeys;
while (true) {
ready = selector.select();
readyKeys = selector.selectedKeys();
System.out.println("Ready channels: " + ready);
System.out.println("Selected channels: " + readyKeys.size());
if (ready == 0) {
continue;
}
for (SelectionKey key : readyKeys) {
if (key.isValid() && key.isReadable()) {
// Take action...
}
readyKeys.remove(key);
}
}
Run Code Online (Sandbox Code Playgroud)
select()尽管有一个现成的频道,为什么返回0?建议的处理方法是什么?
编辑:
改变这个:
for (SelectionKey key : readyKeys) {
if (key.isValid() && key.isReadable()) {
// Take action...
}
readyKeys.remove(key);
}
Run Code Online (Sandbox Code Playgroud)
对此
for (SelectionKey key : readyKeys) {
readyKeys.remove(key);
if (key.isValid() && key.isReadable()) {
// Take action...
}
}
Run Code Online (Sandbox Code Playgroud)
解决了这个问题.在某些情况下,代码将continue在for循环之前remove()荷兰国际集团的关键.
编辑2:
我刚刚了解到我对所选键集的foreach循环不好.foreach使用set的迭代器.在迭代时直接修改集合(而不是通过迭代器的方法)可能会导致"任意的,不确定的"行为.
所选键集可以提供快速失败的迭代器.失败快速迭代器检测此类修改并在下一次迭代时抛出ConcurrentModificationException.因此,在foreach中修改集合可能会导致不确定行为,也可能导致异常 - 具体取决于迭代器实现.
解决方案:不要使用foreach.使用迭代器并通过iterator.remove()删除密钥.
Iterator<SelectionKey> iterator;
SelectionKey key;
while (true) {
// ...
iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
key = iterator.next();
iterator.remove();
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
select()返回已更改的键数.因此,如果一个密钥在select()调用之前已经准备就绪,那么它可以返回0但selectedKeys可以是非空的.
| 归档时间: |
|
| 查看次数: |
6405 次 |
| 最近记录: |