NIO Selector: Как правильно зарегистрировать новый канал при выборе
У меня есть подклассThread
с частнымSelector
и общественностьregister(SelectableChannel channel, ...)
метод, который позволяет другим потокам регистрировать каналы для селектора.
Как ответилиВотканалregister()
блоки во время селектора /select()
select(long timeout)
поэтому нам нужноwakeup()
селектор.
Мой поток выбирает бесконечно (если он не прерывается), и ему действительно удается перейти к следующему выбору перед каналомregister()
называется. Поэтому я подумал, что я использую простой замок сsynchronized
блоки для обеспеченияregister()
случается первым
Код: (нерелевантный код удален для удобства чтения)
public class SelectorThread extends Thread {
...
public void register(SelectableChannel channel, Attachment attachment) throws IOException {
channel.configureBlocking(false);
synchronized (this) { // LOCKING OCCURS HERE
selector.wakeup();
channel.register(selector,
SelectionKey.OP_READ,
attachment);
}
}
@Override
public void run() {
int ready;
Set readyKeys;
while (!isInterrupted()) {
synchronized (this) {} // LOCKING OCCURS HERE
try {
ready = selector.select(5000);
} catch (IOException e) {
e.printStackTrace();
continue;
}
if (ready == 0) {
continue;
}
readyKeys = selector.selectedKeys();
for (SelectionKey key : readyKeys) {
readyKeys.remove(key);
if (!key.isValid()) {
continue;
}
if (key.isReadable()) {
...
}
}
}
}
}
Этот простой замок позволяетregister()
произойдет до того, как поток продолжит следующий цикл выбора. Насколько я проверял, это работает как положено.
Вопросы: Это "хорошо" способ сделать это или есть серьезные недостатки в этом? Было бы лучше использовать список или очередь (как предложеноВот) хранить каналы для регистрации или более сложные блокировки вродеэтот вместо? Какими бы были плюсы / минусы этого? Или есть лидаже лучше" пути?