W tym wykładzie poznamy selektor reprezentowany przez klasę Selector . Klasa znajduje się w pakiecie java.nio.channels , więc nie trzeba niczego pobierać ani konfigurować, aby z niej korzystać. Obiekt typu Selector może śledzić jeden lub więcej obiektów typu Channel , sprawdzać ich gotowość do odczytu/zapisu itp. I co najważniejsze: selektor potrzebuje jednego wątku, a nie jednego wątku na kanał.

Selektory tworzymy metodą static open :

Selector selector = Selector.open();

Następnie kanały można zarejestrować w obiekcie selektora:

SelectionKey key1 = channel1.register(selector, SelectionKey.OP_READ);
SelectionKey key2 = channel2.register(selector, SelectionKey.OP_WRITE);

Drugi parametr metody register określa, jaką operację będzie monitorował selektor. Jeśli chcesz monitorować kilka operacji jednocześnie, możesz użyć bitowego OR:

SelectionKey.OP_READ | SelectionKey.OP_WRITE

Gdy na którymś z kanałów wystąpi akcja I/O, selektor nas o tym powiadamia. W ten sposób możliwe jest np. odczytywanie danych z dużej liczby źródeł danych.

Należy tutaj zauważyć, że aby kanał mógł być używany z selektorem, musi być w tak zwanym trybie nieblokującym:

channel1.configureBlocking(false);
channel2.configureBlocking(false);
SelectionKey key1 = channel1.register(selector, SelectionKey.OP_READ);
SelectionKey key2 = channel2.register(selector, SelectionKey.OP_WRITE);

Wynika z tego, że selektor nie będzie działał z FileChannel , ponieważ FileChannel nie może zostać przełączony w tryb nieblokujący ( metoda configureBlocking jest zadeklarowana w klasie SelectableChannel , a FileChannel jej nie dziedziczy).

Na diagramie widać, że selektory są odpowiednie do użycia z gniazdami. Będziemy z nimi pracować pod koniec drugiego modułu.

Klucz wyboru

Rejestrując kanał selektorem otrzymujemy obiektKlucz wyboru. Ten obiekt zawiera dane reprezentujące rejestrację kanału.

Z klucza możesz określić, czy kanał jest gotowy na określoną wartość:

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

Z klucza możesz uzyskać odpowiedni kanał i selektor:

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

Możesz przyczepić dowolny przedmiot do klucza, aby śledzić go w przyszłości. Można to zrobić albo podczas rejestracji kanału (z trzecim argumentem), albo później:

  1. Klucz SelectionKey = channel.register(selektor, SelectionKey.OP_ACCEPT, obiekt);

  2. klucz.dołącz(obiekt);

W przyszłości możesz uzyskać dołączony obiekt z klucza:

Object object = key.attachment();

Wniosek

Po zarejestrowaniu kanałów selektorem możemy:

  • dowiedzieć się, ile kanałów jest gotowych do wykonania określonych operacji;
  • zablokować wykonywanie programu do momentu pojawienia się co najmniej jednego gotowego kanału;
  • zdobądź wiele kluczy gotowych kanałów;
  • i inne.

Na koniec drugiego modułu przetestujemy selektory w praktyce.