java 为什么在通过密钥时会收到 CancelledKeyException?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6215065/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why do I get CancelledKeyException when going through the keys?
提问by Rihards
Why do I get the CancelledKeyException
few times a day? Should I do something about it? Is my code wrong?
为什么我CancelledKeyException
一天收到几次?我应该做些什么吗?我的代码有错吗?
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key = (SelectionKey) keys.next();
keys.remove();
try {
if (key.isValid()) {
if (key.isReadable()) {
readHandler.handle((Connection) key.attachment());
}
if (key.isWritable()) {
writeHandler.handle((Connection) key.attachment());
}
if (key.isAcceptable()) {
acceptHandler.handle(key);
}
}
} catch (CancelledKeyException e) {
_logger.error("CanceledKeyException in while loop:", e);
}
}
Exception:
例外:
java.nio.channels.CancelledKeyException: null
at sun.nio.ch.SelectionKeyImpl.ensureValid(SelectionKeyImpl.java:55) ~[na:1.6.0_12]
at sun.nio.ch.SelectionKeyImpl.readyOps(SelectionKeyImpl.java:69) ~[na:1.6.0_12]
at java.nio.channels.SelectionKey.isWritable(SelectionKey.java:294) ~[na:1.6.0_12]
at project.engine.io.SimpleReactor.work(SimpleReactor.java:194) ~[engine-02.06.11.jar:na]
at project.server.work.AbstractWorker.run(AbstractWorker.java:20) [server-21.05.11.jar:na]
at java.lang.Thread.run(Thread.java:619) [na:1.6.0_12]
采纳答案by user207421
One of the handlers may close the channel. For example, the read handler shouldclose the channel if it reads a -1. So the write handler will then fail. Indeed isWritable()
will fail, as I can now see from your stack trace. So you must test isValid()
with every other condition, e.g. isValid() && isReadable(),
isValid() && isWritable(),
etc.
处理程序之一可能会关闭通道。例如,如果读取处理程序读取到 -1,它应该关闭通道。因此写入处理程序将失败。确实isWritable()
会失败,正如我现在可以从您的堆栈跟踪中看到的那样。因此,您必须isValid()
在所有其他条件下进行测试,例如isValid() && isReadable(),
isValid() && isWritable(),
等。
回答by Eduardo Bezerra
EJP's solution doesn't seem to be the ideal one... I think the correct way to handle a selection key that was canceled in the middle of the selector loop is to surround it with a try/catch and check for a CancelledKeyException
, as in:
EJP 的解决方案似乎不是理想的解决方案......我认为处理在选择器循环中间取消的选择键的正确方法是用 try/catch 包围它并检查 a CancelledKeyException
,如:
try {
if (key.isReadable())
processMessage(key);
if (key.isAcceptable())
acceptConnection(key);
}
catch (CancelledKeyException e) {
logger.debug("Key cancelled... Closing channel.");
key.channel().close();
}
回答by Heymen Nicolaij
In my case the thread doing the cancel is a different one than the one which registers the channel for selection. It seems this exception happens when the key is being cancelled first and next the other thread is registering the key again without a select in between. So I solved it by just doing a dummy select just prior to registering the channel again for select. It seems some bookkeeping is done in the select which is neccessary for the registration action to be succesful. Both threads use synchronized blocks (3 in total) on a shared static object to lock the registration, cancel and select action respectively.
在我的情况下,执行取消的线程与注册通道以供选择的线程不同。当密钥首先被取消,然后另一个线程再次注册密钥而没有选择时,似乎会发生此异常。所以我通过在再次注册频道进行选择之前做一个虚拟选择来解决它。似乎在选择中进行了一些簿记,这是注册操作成功所必需的。两个线程在共享静态对象上使用同步块(共 3 个)分别锁定注册、取消和选择操作。