Hello, Freakin world!

[Java][NIO] Selector 정리 본문

프로그래밍 언어/Java

[Java][NIO] Selector 정리

johnna_endure 2020. 3. 7. 11:25

이 문서는 java12 documentation 내용을 정리한 것입니다.

 

이 객체는 SelectableChannel 객체의 멀티플렉서입니다. 

멀티플렉서란 아래 그림처럼 다중의 입력을 하나의 출력으로 반환하는 걸 매개하는 것을 의미합니다.

 

출처 : https://i.stack.imgur.com/MobgJ.png

 

Selector 객체는 Selector 클래스의 open 메서드를 호출함으로서 생성됩니다.

내부적으로 미리 설정된 기본 selector provide 객체를 통해서 새로운 selector를 만듭니다.

Selector 객체는 커스텀 selector provider의 openSelector 메서드를 이용해서 제공될 수도 있습니다.

Selector는 close()로 인해 닫히기 전까지 열려있는 상태를 유지합니다.

 

Selectable channel을 등록하면 SelectionKey를 통해 channel에 접근할 수 있습니다.

 

selector는 세 종류의 key set을 가집니다.

key set

Selector에 등록된 channel들의 key(SelectionKey)로 이루어진 set입니다.

이 set은 keys 메서드에 의해 반환됩니다.

selected-key set

이전 selection 작업에서 add하거나 update 했던 channel의 interest operation에 대해서 operation을 실행할 준비가 된 경우 감지되어 selected-key set에 추가됩니다. 그리고 이 set은 selectedKeys 메서드에 의해 반환됩니다. 이 set은 항상 key set의 부분집합입니다.

cancelled-key set

취소되어질 key들의 set입니다. cancelled-key set에 key가 추가되는 것만으로 channel은 등록해제 되지 않습니다. 등록해제는 다음 selection 작업에 이루어집니다.

cancelled-key setkey set 의 부분집합이며, 직접 접근할 수 없습니다.


selector가 새로 생성될 경우, 위 세 개의 set들은 비어있는 상태입니다.

 

register() 를 이용해 channel을 등록하면, side effect로 key는 key set에 추가됩니다.

cancelled key에 등록된 key들은 key set에서 selection 작업 중 제거됩니다.

key set은 직접 수정할 수 없습니다.

 

channel 객체에서 close()를 호출하거나 key 객체에서 cancel()를 호출하면 key는 cancelled-key set에 추가됩니다. 

그리고 다음 selection 작업 때, 그 key에 해당하는 channel은 등록해제되고 모든 종류의 key set에서 해당 키가 제거됩니다.

 

key들은 selection 작업을 통해서 selected-key set에 추가됩니다.

key는 selected-key set에서 remove 메서드를 통해 직접적으로 제거될 수 있습니다.

그리고 set의 clear() 를 통해서 모든 키들을 제거할 수 있습니다.

key들을 직접적으로 selected-key set에 추가하는 것은 권장되지 않습니다.

 

Selection

selection 작업동안 selector의 selected-key set 내부에서 key 들의 추가,제거 작업이 일어납니다.

그리고 cancelled-key set에서 key들이 제거되기도 합니다. 

 

selection은 select(), select(long), selectNow() 메서드에 의해 실행됩니다. 

selection 작업은 다음 세가지 과정을 포함합니다.

 

1. cancelled-key set에 추가된 key는 모든 종류의 key set들에서 key가 제거되도록 합니다.

그리고 key에 해당하는 channel은 등록해제됩니다. cancelled-key set에 포함된 모든 key들에 대해 작업이 수행되고, 모두 끝나면 cancelled-key set은 완전히 비워집니다.

 

2. selector는 selection 시작시 channel에 지정된 interest operation들이 준비되어 있는지 검사합니다.

해당 interest operation에 대한 작업이 준비되었는지 확인하기 위해 내부에서 OS에 요청을 보냅니다.

적어도 하나의 channel이 interest operation들에 대한 준비가 끝나 실행할 준비가 되었다면

다음 두 아래 두 가지 중 하나가 실행됩니다. 

 

 - 해당 key가 selected-key set에 존재하지 않는 경우.

key는 selected-key set에 추가되고, channel 등록시 지정했던 interest operation들에 대해, 실행할 준비가 끝난 operation들을 정확히 식별하기 위해서 ready-operation set(비트로 이루어진 set)을 수정합니다. 그리고 이전에 기록된 ready-operation set은 폐기됩니다.

 

- 해당 키가 이미 selected-key set에 존재하는 경우.

마찬가지로 ready-operation set을 수정하지만, 이전에 기록된 정보들은 유지됩니다.

ready-operation set에 비트 단위로 분리되어 저장됩니다.( <-- 이 부분의 해석은 애매함. 테스트 필요)

 

 만약 key set의 모든 key들이 이 과정을 시작하는 시점에 비어있는 interest operation set을

가진다면 selected-key set이나 key들의 ready-operation set이 업데이트 되지 않습니다.

 

3. key가 2번 과정이 진행 중에 cancelled-key set에 추가되는 경우, 그 키는 1번 과정에서 처리됩니다.

 

세 가지 selection 메서드 사이의 중요한 차이는 channel을 기다리기 위해 블락되는지의 여부입니다.

 

Concurrency

 

selector와 key set은 스레드 세이프합니다.

하지만 selected-key set과 cancelled-set은 스레드 세이프하지 않습니다.

 

selection 작업은 selector 객체, key set, selected-key set 순서로 동기화합니다.

cancelled-key set은 위의 1번과 3번 과정에서 동기화힙니다.

 

selection 작업 중 selector의 key의 interest set의 변화는 현재 작업에 영향을 주지 않습니다.

그 변화들은 다음 selection 작업에서 처리됩니다.

 

key들과 channel들은 언제든지 cancel 되거나 close 될 수 있습니다.

그런 이유로 하나 이상의 key가 key set에 존재한다고 해서, 그 키가 유효하거나 그 channel이 open 상태라는 것을 의미하지 않습니다.

어플리케이션 코드는 신중하게 이런 조건들을 동기화하고 필요에 다른 스레드가 key를 cancel하거나 channel을 close할 가능성은 없는지 체크해야합니다.

 

select()나 select(long) 메서드에 의해 블락된 스레드는 세 가지 방법에 의해서 인터럽트될 수 있습니다.

- selector의 wakeup 메서드 호출에 의해

- selector의 close 메서드 호출에 의해

- 블락된 스레드의 interrupt 메서드 호출에 의해서. 이 경우에 스레드는 interrupt 상태가 되고, selector의 wakeup 메서드가 호출됩니다.

 

close 메서드는 selector 객체와 selected-key set을 selection 작업에서와 동일한 순서로 동기화합니다.

 

selector의 key set은 스레드 세이프합니다. key set을 검색하고 조회하는 작업은

보통 블락되지 않기 때문에 channel의 등록이나 selection 작업 중 cancellation 과정이 오버랩되어

일어날 수 있습니다. Iterator와 Spliterator들은 이들이 생성된 이후 또는 어떤 시점에서

set의 상태를 나타내는 요소를 반환합니다. 이 과정에서 Iterator와 Spliterator는  

ConcurrentModificationException를 반환하지 않습니다.

 

selector의 selected-key set은 보통 스레드 세이프하지 않습니다.

다중 스레드 환경에서 그중 하나의 스레드가 set을 직접적으로 수정하는 경우,

set 자체를 동기화시킴으로서 접근이 제어되어야 합니다.

만약 set이 iterator가 생성된 이후에 수정되는 경우, iterator 자신만의 메서드(remove)를 

제외하고,  ConcurrentModificationException 예외가 발생합니다.

Comments