자바 NIO는 New IO의 줄임말이라고 합니다.
그런데 기존에 IO 라이브러리가 제공이 되었는데 왜 그렇다면 이 NIO가 새로이 등장하였을까? 답은 입출력을 하는 방식의 차이에 있습니다. 이번 포스트에서는 IO와 NIO가 가지고 있는 차이점에 대해 간략하게 알아보는 시간을 갖도록 하겠습니다.
1. 입출력 방식
자바 IO에서는 입출력이 바이트 단위로 혹은 문자 단위로 이루어 집니다. 바이트 단위로 이루어지는 경우에는 InputStream / OutputStream을, 문자 단위로 이루어지는 경우에는 Reader / Writer를 사용합니다. 입력과 출력에 따라 각각 별도로 InputStream / Reader 혹은 OutputStream / Writer를 생성해 주어야 합니다.
한편 NIO에서는 입출력이 채널 (Channel)을 통해 이루어 집니다. IO에서 입력과 출력이 구분되어 있는 것에 반해 채널은 양방향 소통이 가능합니다. 파일을 읽고 쓰는 경우를 예로 들자면 FileChannel 하나만 생성해 주면 됩니다.
2. 버퍼
버퍼라는 개념에 대해서는 이전에 작성한 포스트에서 확인해 보실 수 있습니다. (여기를 클릭해 주세요)
IO에서는 버퍼의 사용이 필수가 아닙니다. 물론 성능 문제상 버퍼를 사용하는 것이 권장되긴 하지만, BufferedReader나 BufferedWriter 등 클래스가 별도로 존재하여 이들을 함께 활용하지 않는 이상 버퍼 없는 입출력을 만들 수 있습니다.
NIO에서는 기본적으로 버퍼를 사용해서 입출력을 하도록 설계되어 있다는 점이 IO와 다릅니다. 채널은 버퍼에 저장된 데이터를 출력하고 버퍼에 데이터를 입력하는 방식이 NIO의 기본입니다.
3. 블로킹? 넌블로킹?
좀 더 쉽게 설명하기 위해 한가지 사례를 들겠습니다. 사원 A랑 B에게 각각 보고서를 작성하라는 일을 시켰습니다. 그리고 일을 하는 도중에 양쪽 모두에게 커피를 타오라는 일과 문서 복사를 해오라는 일을 추가했다고 가정합시다. A는 멀티태스킹이 되지 않는 사람이라 보고서를 먼저 작성하고 그 다음에 커피를 타오고 마지막으로 복사를 한 반면, B는 보고서를 작성하는 도중에 시킨 일들을 도중에 다 했습니다. A 사원의 업무 스타일에 해당하는게 바로 IO이고 B사원에게 해당하는게 NIO라고 할 수 있겠습니다.
IO에서 read() 메소드를 호출하여 내용을 읽어들인다고 했을 때, 데이터가 입력되기 전까지 작업 쓰레드는 대기 상태로 전환되며, 이를 블로킹이라고 합니다. 블로킹 상태에 있는 동안 이 쓰레드는 다른 작업을 수행할 수 없고, 인터럽트를 통해 블로킹을 빠져나올 수도 없습니다.
NIO는 넌블로킹이랑 블로킹이 둘다 가능하도록 되어 있습니다. 그런데 블로킹에서도 IO와 한가지 중요한 차이점이 있는데 그것은 바로 NIO에서는 블록된 상태에서도 인터럽트가 가능하도록 되어 있다는 것입니다. 넌블로킹의 핵심은 바로 셀렉터 (Selector)인데요, 여러개의 채널 중에서 바로 읽고 쓸 준비가 완료된 채널을 제공하는 역할을 합니다. 이렇게 제공된 채널만을 가지고 작업 쓰레드가 처리하기 때문에 넌블로킹 방식이라고 말할 수 있습니다.
지금까지 NIO에 대한 개관이었구요, 다음 포스트에서는 NIO의 각 클래스를 소개하면서 이를 활용한 예시 코드를 함께 제공하며 설명하도록 하겠습니다.