Я бы предположил, что предложенный фрагмент не будет работать вообще, в соответствии с контрактами Selector#select()
и Selector#selectedKeys()
. От Селектор :
- Набор выбранных ключей - это набор ключей, так что канал каждого ключа был обнаружен готовым по крайней мере к одной из операций, определенных в наборе интересов ключа во время предыдущей операции выбора. Этот набор возвращается методом selectedKeys.
public abstract int select(long timeout)
throws IOException
Returns:
The number of keys, possibly zero, whose ready-operation sets were
updated
Когда я это прочитал, размер набора selectedKeys
всегда должен совпадать с числом, возвращаемым select
по определению. Я заметил - как и вы, возможно, также - что некоторые реализации не совсем следуют документации, и фактически selectedKeys
возвращает все ключи с обновленными наборами готовых операций, даже если они не были обновлены во время вызова select
. Единственный другой индикатор того, что селектор проснулся из-за вызова wakeup
, может заключаться в том, что количество клавиш равно нулю; однако любой из этих методов в лучшем случае был бы ненадежным.
Обычный способ справиться с этим, как подразумевается, через контроль параллелизма. Я не буду беспокоиться о времени выполнения здесь; это классический пример преждевременной оптимизации .
Если вы действительно не беспокоитесь о допусках в одну микросекунду, вы не заметите никакого замедления - и если вас беспокоит этот уровень допуска, то Selector
не будет достаточно надежным для вас в любом случае.
Вот пример обычного механизма для этого, использующего ReentrantLock
для достижения соответствующего параллелизма:
ReentrantLock selectorGuard;
Selector selector;
private void doSelect() {
// Don't enter a select if another thread is in a critical block
selectorGuard.lock();
selectorGuard.unlock();
selector.select();
Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
while(keyIter.hasNext()) {
SelectionKey key = keyIter.next();
keyIter.remove();
// Process key
}
}
private void addToSelector() {
// Lock the selector guard to prevent another select until complete
selectorGuard.lock();
try {
selector.wakeup();
// Do logic that registers channel with selector appropriately
} finally {
selectorGuard.unlock();
}
}