У цій лекції ми познайомимося із селектором, що представлений класом Selector. Клас знаходиться в пакеті java.nio.channels, тому для його використання не треба буде нічого завантажувати або налаштовувати. Об’єкт типу Selector може стежити за одним або декількома об’єктами типу Channel, перевіряти їхню готовність до читання/запису тощо. І головне: для selector потрібен один потік, а не по одному потоку на кожен канал.

Створюємо селектор за допомогою статичного методу 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 його не наслідує).

Зі схеми ти можеш побачити, що селектори доречно використовувати із сокетами. З ними ми попрацюємо наприкінці другого модуля.

SelectionKey

Під час реєстрації каналу за допомогою селектора ми отримуємо об’єкт SelectionKey. Цей об’єкт містить дані, що представляють реєстрацію каналу.

Із ключа можна визначити, чи готовий канал до певного значення:


key.isReadable()
key.isAcceptable()
key.isConnectable()
key.isWritable()

Із ключа можна отримати відповідні канал та селектор:


Channel channel = key.channel();
Selector selector = key.selector();

До ключа можна прикріпити будь-який об’єкт, щоб у подальшому його відстежувати. Це можна зробити як під час реєстрації каналу (третім аргументом), так і пізніше:

  1. SelectionKey key = channel.register(selector, SelectionKey.OP_ACCEPT, object);

  2. key.attach(object);

У подальшому із ключа можна отримати прикріплений об’єкт:


Object object = key.attachment();

Висновок

Після реєстрації каналів за допомогою селектора ми можемо:

  • дізнатися кількість каналів, готових до виконання заданих операцій;
  • заблокувати виконання програми до появи принаймні одного готового каналу;
  • отримати безліч ключів готових каналів;
  • та інше.

Наприкінці другого модуля будемо випробовувати селектори на практиці.