Почему я получаю CancelledKeyException при прохождении через ключи? - PullRequest
11 голосов
/ 02 июня 2011

Почему я получаю 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);
            }
        }

Исключение:

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$1.run(AbstractWorker.java:20) [server-21.05.11.jar:na]
    at java.lang.Thread.run(Thread.java:619) [na:1.6.0_12]

Ответы [ 3 ]

7 голосов
/ 04 июня 2011

Один из обработчиков может закрыть канал. Например, обработчик чтения должен закрыть канал, если он читает -1. Таким образом, обработчик записи потерпит неудачу. Действительно, isWritable() потерпит неудачу, как я теперь вижу по трассировке стека. Таким образом, вы должны проверить isValid() с любым другим условием, например, isValid() && isReadable(), isValid() && isWritable(), и т. Д.

0 голосов
/ 12 октября 2017

В моем случае поток, выполняющий отмену, отличается от потока, который регистрирует канал для выбора.Кажется, это исключение происходит, когда ключ отменяется первым, а затем другой поток снова регистрирует ключ без промежуточного выбора.Поэтому я решил это, просто сделав фиктивный выбор перед тем, как снова зарегистрировать канал для выбора.Похоже, что в системе выбора выполняется некоторая бухгалтерия, которая необходима для успешной регистрации.Оба потока используют синхронизированные блоки (всего 3) для общего статического объекта для блокировки регистрации, отмены и выбора действия соответственно.

0 голосов
/ 17 февраля 2014

Решение EJP не кажется идеальным ... Я думаю, что правильный способ обработки клавиши выбора, которая была отменена в середине цикла селектора, - это окружить его методом try / catch и проверить наличие CancelledKeyException, как в:

try {
   if (key.isReadable())
      processMessage(key);

   if (key.isAcceptable())
      acceptConnection(key);
}
catch (CancelledKeyException e) {
   logger.debug("Key cancelled... Closing channel.");
   key.channel().close();
}
...