NIO
в основном используется на стороне сервера для обработки больших объемов. Я попытаюсь объяснить, как работает типичный сервер.
На сервере есть очередь запросов, из которой поток опроса потребляет соединения как операцию blocking dequeue
(в Java длина запросов по умолчанию queue - 50. Это означает, что если вы попытаетесь инициировать 51-е соединение, пока очередь запросов заполнена, вы получите исключение ConnectionRefused
).
Типичная реализация blocking
выглядит следующим образом:
Сервер принимает соединение и помещает его в requests queue
.
Опрос thread
потребляет соединения из заголовка очереди и отправляет его в а thread pool
. Поток опроса становится свободным, если очередь thread-pool
не заполнена, и продолжает использовать соединения из queue
.
В какой-то момент все потоки в пуле потоков станут занято, и поток опроса будет заблокирован при отправке дополнительных подключений в пул (поскольку очередь пула потоков - это blocking queue
).
requests queue
начинает заполняться в тем временем. В какой-то момент он полностью заполнится, и сервер больше не будет принимать какие-либо соединения.
На этом этапе наш сервер просто больше не может масштабироваться. Обратите внимание, что «занятые» потоки в пуле могут быть совсем не заняты, а просто заблокированы - скажем, для получения дополнительных данных на InputStream
соответствующего сокета, который они обслуживают.
Теперь рассмотрим эту схему:
Поток опроса потребляет элементы из заголовка очереди запросов.
Он помещает его в неограниченный список.
Другой поток непрерывно просматривает этот список и проверяет, произошла ли какая-либо активность в сокете (чтение для чтения, готовность к записи и т. Д. c). Если есть активность, обслуживается socket
. Обратите внимание, что эти sockets
работают в режиме NIO
. То есть, если нет активности, наш поток не будет заблокирован.
Тем временем поток опроса продолжает отправлять подключения к списку, поскольку список неограничен. Он нигде не блокируется (кроме тех случаев, когда он ожидает нового соединения в очереди запросов).
Обратите внимание, что наш масштаб ограничен только нашими системными ресурсами. - а именно, сколько соединений держит list
. Время отклика существенно снизится, поскольку все соединения обслуживает только один поток. Потребление ЦП будет довольно высоким из-за бессмысленной итерации. Но вы все равно сможете подключиться к серверу, в отличие от предыдущего дизайна.
NIO
в основном решает эту проблему, используя selectors
.