UML-диаграммы сильно переоценены
Конечно, есть полезные диаграммы, например. Диаграмма классов для Composite Pattern , но многие диаграммы UML не имеют абсолютно никакого значения.
Вы пытались распечатать трассировку стека всех потоков в вашей программе? (с помощью kill -QUIT
в Unix или Ctrl + Break в Windows или с помощью утилиты jstack
)?
AbstractSelectableChannel
содержит блокировку, для которой configureBlocking
и регистр
необходимо синхронизировать. Эта блокировка также доступна через метод blockingLock ()
, и поэтому другой поток потенциально может удерживать блокировку, вызывая блокировку вашего вызова регистра на неопределенный срок (но без трассировки стека это трудно сказать).
You need to use a lock and manually synchronize.
In the same thread you are running the selector loop have a ReentrantLock:
final ReentrantLock selectorLock = new ReentrantLock();
Then when you need to register with the selector do something like this:
selectorLock.lock();
try {
selector.wakeup();
socketChannel.register(selector, ops);
} finally {
selectorLock.unlock();
}
Finally, during your loop that you are calling accept(), something like this:
selectorLock.lock();
selectorLock.unlock();
selector.select(500);
And then continue on with the rest of your logic.
This construct guarantees that the register()
call will not block by ensuring that there is never another select()
between corresponding wakeup()
and register()
calls.
Это является основной особенностью большинства реализаций NIO, которые не очевидно из документации.
Вы должны сделать все регистрационные звонки из того же потока, который выполняет ваш выбор или тупики. Обычно это делается, предоставив очередь регистраций / израсходов / изменений процентов, которые записываются, и затем SELECTOR.Wakeup () называется. Когда выбирающая нить просыпается, она проверяет очередь и выполняет любые запрошенные операции.