Ответ
Неблокирующее чтение позволяет выполнять операции ввода-вывода без остановки основного потока выполнения. В Java это реализуется через NIO (New I/O) API, используя три ключевых компонента:
Selector— мультиплексор, отслеживающий готовность нескольких каналов к операциям.Channel(например,SocketChannel,FileChannel) — абстракция для двусторонней передачи данных.Buffer— контейнер для данных.
Пример использования SocketChannel и Selector:
Selector selector = Selector.open();
SocketChannel channel = SocketChannel.open();
// Переводим канал в неблокирующий режим
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("example.com", 80));
// Регистрируем канал в селекторе для уведомлений о готовности к чтению
channel.register(selector, SelectionKey.OP_READ);
while (true) {
// Блокирует выполнение, пока хотя бы один из зарегистрированных каналов не будет готов
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
for (SelectionKey key : selectedKeys) {
if (key.isReadable()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
// Чтение из канала в буфер. В неблокирующем режиме может вернуть 0, если данных нет.
int bytesRead = ((SocketChannel) key.channel()).read(buffer);
if (bytesRead > 0) {
buffer.flip(); // Подготовка буфера к чтению
System.out.println(new String(buffer.array(), 0, bytesRead));
}
}
}
selectedKeys.clear(); // Очистка набора обработанных ключей
}
Почему это эффективно? Один поток (Selector) может управлять множеством соединений, экономя ресурсы по сравнению с моделью "один поток на соединение", используемой в блокирующем I/O.