Java NIO
자바에서 InputStream, OutputStream과 같이 *Stream으로 통신하는 모델을 Java IO 모델이라고 한다.
- 패키지는
java.io.*에 속한다.
자바 NIO란 New Input/Output의 약자이다. 아래는 Java IO와 Java NIO의 차이이다.
| 구분 | IO | NIO |
|---|---|---|
| 입출력 방식 | Stream | Channel |
| 데이터 단위 | Byte, Character | Buffer |
| 데이터 흐름 | 단방향 | 양방향 |
| 논블로킹 지원 | X | O |
가장 큰 차이는 Java IO는 Stream 기반, NIO는 Channel 기반으로 동작한다.
- NIO는
java.nio.*패키지에 속한다.
NIO는 아래와 같이 Buffer를 통해 데이터를 읽거나 써서 파일과 통신한다.

Java NIO의 모든 IO는 Channel로 시작한다. Channel을 통해 버퍼에서 데이터를 읽거나 버퍼에 데이터를 쓴다.
Buffer는 아래와 같이 다양한 타입을 제공한다.

다음으로 Buffer의 위치 속성을 살펴보자.
- capacity: Buffer가 저장할 수 있는 데이터의 최대 크기
- position: Buffer에서 현재 가르키는 위치
- limit: 데이터를 읽거나 쓸 수 있는 마지막 위치 (읽기 모드 시 주로 사용)
- mark: reset() 호출 시 position을 mark로 이동
해당 속성은 아래의 관계를 가진다.
- 0 <= mark <= position <= limit <= capacity
다음으로 ByteBuffer의 종류에 대해 알아보자.
DirectByteBuffer
DirectByteBuffer는 Native Memory에 저장되는 ByteBuffer이다.
- Native Memory(off-heap)에 저장
- 커널 메모리에서 복사를 하지 않으므로 read/write 속도가 빠르다.
- 비용이 많이 드는 System call을 사용하므 allocate, deallocate가 느리다. (Pool로 만들어서 사용할 수 있다.)
HeapByteByteBuffer
HeapByteBuffer는 JVM Heap에 저장되는 ByteBuffer이다.
- JVM Heap Memory에 저장된다. (byte[] 래핑)
- 커널 메모리에서 복사가 일어나므로 read/write 속도가 느리다.
- gc에서 관리되므로 allocate, deallocate가 빠르다.
아래는 예시 코드이다.
var file = new File(FileChannelReadExample.class
.getClassLoader()
.getResource("hello.txt")
.getFile());
try (var fileChannel = FileChannel.open(file.toPath())) {
var byteBuffer = ByteBuffer.allocate(1024);
fileChannel.read(byteBuffer);
byteBuffer.flip();
var result = StandardCharsets.UTF_8.decode(byteBuffer);
}
DirectByteBuffer를 사용하려면 allocate()대신 ByteBuffer.allocateDirect()를 사용하면 된다.
configureBlocking
아래는 SelectableChannel 이라는 추상 클래스의 configureBlocking() 메서드이다.

해당 메서드의 설명은 "Adjusts this channel's blocking mode." 직역하면 Blocking 모드를 조정한다.
아래는 SelectableChannel을 상속하는 ServerSocketChannel을 비동기로 사용하는 예제이다.
try (var serverChannel = ServerSocketChannel.open()) {
var address = new InetSocketAddress("localhost", 8080);
serverChannel.bind(address);
serverChannel.configureBlocking(false);
var connected = serverChannel.connect(address);
assert !connected; // 통과
}
반면 FileChannel의 경우 SelectableChannel을 상속받지 않는다. 그렇기 때문에 Non-Blocking으로 설정할 수 없다.
여기서 알 수 있듯 Java NIO의 모든 IO가 Non-Blocking하게 동작할 수 있지는 않다.
AIO(NIO2)
Java AIO(Asynchronous Non-Blocking I/O)에서는 Callback 기반의 Channel을 제공해준다.
- NIO2 라고도 부른다.

자바 NIO에서 Non-Blocking IO에서 결과를 받으려면 while문으로 완료 여부를 확인 등의 처리가 필요하다. 자바 AIO에서는 콜백을 잡아서 처리할 수 있다.
추가로 Non-Blocking 기반의 다양한 클래스를 지원한다. (자바 AIO의 AsynchronousFileChannel의 경우 Non-Blocking을 지원한다.)