В этой лекции мы познакомимся с селектором, представленным классом Selector. Класс находится в пакете java.nio.channels, поэтому для его использования не понадобится ничего скачивать или настраивать. Объект типа Selector может следить за одним или несколькими объектами типа Channel, проверять их готовность к чтению/записи и т. д. И главное: для selector нужен один поток, а не по одному потоку на каждый канал.
![](https://cdn.javarush.com/images/article/106e0c9f-4e81-4683-86d4-79edbf1bd47c/original.png)
Создаем селектора с помощью статического метода open:
Selector selector = Selector.open();
После чего в объекте селектора можно регистрировать каналы:
SelectionKey key1 = channel1.register(selector, SelectionKey.OP_READ);
SelectionKey key2 = channel2.register(selector, SelectionKey.OP_WRITE);
Второй параметр в метод register определяет, какую операцию будет мониторить селектор. Если нужно следить сразу за несколькими операциями, можно использовать побитовое ИЛИ:
SelectionKey.OP_READ | SelectionKey.OP_WRITE
Когда на любом из каналов будет происходить действие ввода-вывода, селектор уведомляет нас об этом. Таким образом можно, например, читать данные из большого количества источников данных.
Здесь нужно сделать примечание: чтобы канал можно было использовать с селектором, он должен находиться в так называемом неблокирующем режиме:
channel1.configureBlocking(false);
channel2.configureBlocking(false);
SelectionKey key1 = channel1.register(selector, SelectionKey.OP_READ);
SelectionKey key2 = channel2.register(selector, SelectionKey.OP_WRITE);
Из этого следует, что селектор не будет работать с FileChannel, так как FileChannel нельзя переключить в неблокирующий режим (метод configureBlocking объявлен в классе SelectableChannel, а FileChannel его не наследует).
![](https://cdn.javarush.com/images/article/2aa13b88-38b6-4dfb-9faa-cd9e11f99820/original.png)
Из схемы ты можешь увидеть, что селекторы уместно использовать с сокетами. С ними мы поработаем в конце второго модуля.
SelectionKey
При регистрации канала с помощью селектора мы получаем объект SelectionKey. Этот объект содержит данные, представляющие регистрацию канала.
Из ключа можно определить, готов ли канал к определенному значению:
key.isReadable()
key.isAcceptable()
key.isConnectable()
key.isWritable()
Из ключа можно получить соответствующие канал и селектор:
Channel channel = key.channel();
Selector selector = key.selector();
К ключу можно прикрепить любой объект, чтобы в дальнейшем его отслеживать. Это можно сделать как во время регистрации канала (третьим аргументом), так и позже:
SelectionKey key = channel.register(selector, SelectionKey.OP_ACCEPT, object);
key.attach(object);
В дальнейшем из ключа можно получить прикрепленный объект:
Object object = key.attachment();
Заключение
После регистрации каналов с помощью селектора мы можем:
- узнать количество каналов, готовых к выполнению заданных операций;
- заблокировать выполнение программы до появления хотя бы одного готового канала;
- получить множество ключей готовых каналов;
- и другое.
В конце второго модуля будем испытывать селекторы на практике.