Поток Java блокируется при регистрации канала с помощью селектора, когда вызывается select (). Что делать?

У меня есть основной вопрос. Почему и как метод регистра SelectableChannel может быть при блокировании вызова. Позвольте мне представить сценарий.

Я создал объект Selector в классе Register следующим образом.

<code>private static Selector selector = Selector.open();
</code>

У меня также есть метод в том же классе (Регистрация), чтобы зарегистрировать канал с помощью селектора.

<code>public static SelectionKey registerChannel(SelectableChannel channel, int ops)
                             throws IOException {
   channel.configureBlocking(false);
   return channel.register(selector, ops);
}
</code>

И есть другой класс с именем Request, у которого есть метод, который читает данные из каналов, обрабатывает и вызывает следующий метод для регистрации канала.

<code>selectonKey = Register.register(socketChannel, SelectionKey.OP_READ);
</code>

Здесь на этом этапе поток заблокирован, не давая понять, что он ждет. Я проверил, что селектор открыт. Пожалуйста, предоставьте мне некоторую помощь, чтобы понять, как я могу решить эту проблему. Есть ли замок, который я могу снять.

Любой вклад будет оценен.

Добавление к тому, что я описал. Дальнейшие тесты показали, что если метод Register.register вызывается из того же потока, он может зарегистрироваться, но после этого, если какой-то другой поток пытается вызвать метод, поток не продвигается.

Ответы на вопрос(5)

В том же потоке, в котором вы запускаете цикл выбора, есть ReentrantLock:

final ReentrantLock selectorLock = new ReentrantLock();

Затем, когда вам нужно зарегистрироваться в селекторе, сделайте что-то вроде этого:

selectorLock.lock();
try {
    selector.wakeup();
    socketChannel.register(selector, ops);
} finally {
    selectorLock.unlock();
}

Наконец, во время вашего цикла, который вы вызываете accept (), что-то вроде этого:

selectorLock.lock();
selectorLock.unlock();

selector.select(500);

А затем продолжайте с остальной логикой.

Эта конструкция гарантирует, чтоregister() вызов не будет заблокирован, гарантируя, что никогда не будет другогоselect() между соответствующимиwakeup() а такжеregister() звонки.

 30 мар. 2015 г., 00:45
@DavidB. Это не добавляет задержки к каждой регистрации. Это поток выбора, блокирующий до 500 мс, а не регистрирующий поток, и поток выбора всегда захочет заблокироватьselect() тем не мение. Претензии в ответе у вас в основном неверны.
 16 февр. 2011 г., 02:03
+1 за пример кода. Я второе это, из опыта. Красиво сделано.
 10 янв. 2013 г., 05:48
Это добавляет до 500 мс ненужной задержки каждой регистрации. Используйте подход вstackoverflow.com/a/2179612/448970 вместо.

register вызывает поток селектора, но вы не должны использоватьselector.wakeup как это представило бы условия гонки (представьте, что поток селектора занят обработкой других регистраций и вашегоwakeup не разбудить никого). К счастью, Java NIO предоставляетсяPipe так что вы можете позволить селектору слушать обаregister звонки и другие события.

По сути, вот что нужно сделать:

val registrationPipe = Pipe.open()
registrationPipe.source().configureBlocking(false)
registrationPipe.source().register(selector, ,SelectionKey.OP_READ)
// now start your selector thread

// now to register a call from other threads using message pleaseRegisterMe
registrationPipe.sink().write(pleaseRegisterMe)

// inside your selector thread
val selectionKey = iterator.next()
if (selectionKey.channel() === registrationPipe.source()) {
    registrationPipe.source().read(pleaseRegisterMe)
    // do something with the message pleaseRegisterMe and do the actual register
}

Вотполный рабочий пример.

е (используя либоkill -QUIT в Unix или Ctrl + Break в Windows или с помощьюjstack полезность)?

AbstractSelectableChannel содержит замок, на которомconfigureBlocking а такжеregister нужно синхронизировать. Этот замок также доступен черезblockingLock() метод, и поэтому другой поток потенциально может удерживать блокировку, вызывая блокировку вашего регистрационного вызова на неопределенный срок (но без трассировки стека это трудно сказать).

synchronized (selectorLock2) {
   selector.wakeup();
   synchronized (selectorLock1) {
       channel.register(selector, ops);
   }
}

Ваш селекторный цикл должен выглядеть так:

while (true) {
   synchronized (selectorLock1) {
       selector.select();
   }
   synchronized (selectorLock2) {}

   ....
}
 15 февр. 2018 г., 14:38
Вам нужно только один замок, как показано вstackoverflow.com/a/1112809/194894

которая не очевидна из документации.

Вам нужно сделать все зарегистрированные вызовы из той же ветки, которая делает ваш выбор, или возникнут взаимоблокировки. Обычно это делается путем предоставления очереди регистрации / отмены регистрации / изменения процентов, которая записывается в, а затем вызывается selector.wakeup (). Когда выбранный поток просыпается, он проверяет очередь и выполняет любые запрошенные операции.

 01 окт. 2016 г., 10:36
Предоставленное решение в приведенном выше комментарии неверно, по крайней мере, с учетом объяснения. В зависимости от планирования потоков выбранный поток может завершить весь цикл и повторно войти в select (), прежде чем регистрирующий поток сможет вызвать register ().
 08 авг. 2018 г., 00:53
В текущем Java 8 javadoc эта проблема упоминается только в SelectableChannel.register (). AbstractSelectableChannel.register пропускает любое упоминание (и пропускает некоторые другие детали). У меня был такой код: SocketChannel sc = SocketChannel.open (); , , , sc.register (....); Последняя строка вызывает AbstractSelectableChannel.register (). Поэтому, если вы просматриваете Javadocs в IDE, вы не увидите документ для SelectableChannel.register ().
 30 мар. 2015 г., 00:42
Это основная особенностьall Реализации NIO, которые полностью указаны в Javadoc. Существует три вложенных синхронизации, пока вы находитесь вselect(), а такжеregister() попытки одного из них. Результат не тупик, аblock, который длится только до тех пор, пока не завершится параллельный вызов `select ()`. Решение состоит в том, чтобы позвонитьwakeup() доregister(). Это заставляетselect() разблокировать и вернуть ноль, что освобождает три блокировки, что позволяетregister() требовать того, что ему нужно, и продолжать.

Ваш ответ на вопрос