Это легче понять, если понять потенциальные места, где происходит IO в разных точках обработки запроса от контейнера до кода приложения.Задача коннектора контейнера (BIO / NIO) состоит в том, чтобы принять соединение сокета и передать его потоку, который в какой-то момент времени вызывает метод Servlet GET / POST.Теперь соединитель Tomcat NIO - это, по сути, решение контейнера использовать средство Java NIO ( Selector / Channel ) для обработки нескольких каналов ввода-вывода с меньшим количеством потоков.Selector
предоставляет механизм для мониторинга одного или нескольких каналов NIO и распознавания, когда один или несколько становятся доступными для передачи данных, поэтому в контейнере селектора можно использовать один поток вместо нескольких для управления несколькими каналами.Эти готовые каналы затем обслуживаются потоками, число которых потенциально меньше, чем требуется в разъеме BIO.
В качестве отступления - на этом уровне проводится оптимизация уровня ОС для улучшения работы NIO.Например, Java поставляется с java.nio.channels.SelectorProvider
реализацией, основанной на средствах уведомления о событиях epoll в Linux.Средство epoll
доступно в ядрах Linux 2.6 и новее.Новая реализация SelectorProvider, основанная на epoll, является более масштабируемой, чем традиционная реализация SelectorProvider, основанная на опросе, когда в Selector зарегистрированы тысячи SelectableChannel.Новая реализация SelectorProvider будет использоваться по умолчанию при обнаружении ядра 2.6.Основанный на опросе SelectorProvider будет использоваться при обнаружении ядра до 2.6.
Теперь вернемся к рассматриваемой проблеме.До Servlet 3.0 вся обработка сервлета была синхронной, что было улучшено в Servet 3.0, так что метод GET / POST теперь возвращается немедленно, но без записи в ответ, если он не считается завершенным вызовом AsyncContext
complete
.Все идет нормально.Но была другая проблема.Обработка сервлета может потенциально включать чтение / запись во входной поток / выходной поток, доступный из запроса.Природа этого IO была все еще традиционной.Servlet 3.0 допускает асинхронную обработку запросов, но чтение / запись ввода-вывода по-прежнему было старым стилем, например, при чтении полезной нагрузки большого запроса от клиента с низкой скоростью поток блокировал бы ожидание данных - поэтому Servlet 3.1 неблокирует ввод-вывод для спасения, гдетеперь вы можете вызывать стиль обратного вызова вашей логики чтения / записи всякий раз, когда данные готовы, а не ожидающий их потокКак это работает в коде, можно увидеть здесь .
Мы все еще должны помнить, что IO базы данных (если таковой имеется) все еще остается традиционным IO ожидания.Эта область контролируется драйверами базы данных, которые придерживаются JDBC API и знают, что когда-нибудь они также предоставят API для неблокирующего ввода-вывода.Oracle уже ведет одну из таких инициатив Асинхронный доступ к базе данных , которая также похоже на использование Java NIO.Это проложит путь к тому, чтобы сделать обработку всех запросов неблокируемой.