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

14

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

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

private static Selector selector = Selector.open();

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

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

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

selectonKey = Register.register(socketChannel, SelectionKey.OP_READ);

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

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

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

Ваш Ответ

5   ответов
10

В том же потоке, в котором вы запускаете цикл выбора, есть 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() звонки.

@DavidB. Это не добавляет задержки к каждой регистрации. Это поток выбора, блокирующий до 500 мс, а не регистрирующий поток, и поток выбора всегда захочет заблокироватьselect() тем не мение. Претензии в ответе у вас в основном неверны.
+1 за пример кода. Я второе это, из опыта. Красиво сделано.
Это добавляет до 500 мс ненужной задержки каждой регистрации. Используйте подход вstackoverflow.com/a/2179612/448970 вместо.
0

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

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

0

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
}

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

0

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

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

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

   ....
}
Вам нужно только один замок, как показано вstackoverflow.com/a/1112809/194894
34

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

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

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

Похожие вопросы