자바 4부터 새로운 입출력(New Input Output)이라는 뜻에서 java.nio 패키지에 포함 되었는데 자바 7로 버전 업그레이드 되면서 자바 IO 와 NIO 사이의 일관성 없는 클래스 설계를 바로 잡고 비동기 채널 등의 네트워크 지원을 대폭 강화한 NIO.2 API가 추가되었다.
NIO.2는 java.nio의 하위 패키지(java.nio.channels, java.nio.charset, java.nio.file)에 통합되어 있음
JVM이라는 프로세스 위에서 동작하는 추상화된 비교적 고수준의 언어이기 때문에 자바는 느리다.
기타 GC(Garbage Collection)의 메모리 점유 문제등 느린 이유는 많이 있지만 그중 I/O 처리 문제점을 개선하고자 나온 패키지가 java.nio이다.
NIO 패키지 | 포함되어 있는 내용 |
---|---|
java.nio | 다양한 버퍼 클래스 |
java.nio.channels | 파일 채널, TCP 채널, UDP 채널 등의 클래스 |
java.nio.channels.spi | java.nio.channels 패키지를 위한 서비스 제공자 클래스 |
java.nio.charset | 문자셋, 인코더, 디코더 API |
java.nio.charset.spi | java.nio.charset 패키지를 위한 서비스 제공자 클래스 |
java.nio.file | 파일 및 파일 시스템에 접근하기 위한 클래스 |
java.nio.file.attribute | 파일 및 파일 시스템의 속성에 접근하기 위한 클래스 |
java.nio.file.spi | java.nio 패키지를 위한 서비스 제공자 클래스 |
구분 | IO | NIO |
---|---|---|
입출력 방식 | 스트림 방식 | 채널 방식 |
버퍼 방식 | 논버퍼 | 버퍼 |
비동기 방식 | 지원 안함 | 지원 |
블로킹/논블로킹 방식 | 블로킹방식만 지원 | 블로킹/논블로킹 둘다 지원 |
스트림 지향적인 Java IO는 스트림에서 한 번에 하나 이상의 바이트를 읽는다는 것을 의미한다. 스트림에서 읽은 데이터를 앞뒤로 이동해야 하는 경우 먼저 버퍼에 캐시해야 한다.
IO는 스트림 기반 => 스트림은 입력 스트림과 출력 스트림이 구분되어 있음
Java NIO의 버퍼 지향 접근 방식은 약간 다르다. 데이터는 나중에 처리되는 버퍼로 읽는다. IO 방식과 다르게 필요에 따라 버퍼에서 앞뒤로 이동할 수 있으며 이러한 방식으로 인해서 처리하는 동안 더 많은 유연성을 얻을 수 있다.
그러나 버퍼를 완전히 처리하는 데 필요한 모든 데이터가 버퍼에 포함되어 있는지도 확인해야 하고 버퍼에 더 많은 데이터를 읽을 때 아직 처리하지 않은 버퍼의 데이터를 덮어쓰지 않도록 해야한다.
채널은 스트림과는 다르게 양방향 입출력 가능. 때문에 입력과 출력을 위한 별도의 채널을 만들 필요 없음
Java IO의 다양한 스트림이 블로킹 처리가 된다. 즉, 스레드가 read() 또는 를 호출하면 write() 읽을 데이터가 있거나 데이터가 완전히 쓰여질 때까지 해당 스레드는 대기상태가 되고. 그 동안 스레드는 다른 작업을 수행할 수 없다.
IO스레드가 블로킹되면 다른 일을 할 수 없고 블로킹을 빠져나오기 위해 인터럽트할 수도 없음. 유일한 방법은 스트림을 닫는 것
Java NIO의 논블록킹을 사용하면 스레드가 채널에서 데이터 읽기를 요청할 수 있으며 현재 사용 가능한 데이터만 가져오거나 현재 사용 가능한 데이터가 없는 경우 아무 것도 가져오지 않는다. 데이터를 읽을 수 있을 때까지 블로킹 상태로 유지하는 대신 스레드는 다른 작업을 계속할 수 있다.
NIO 논블로킹의 핵심 객체는 멀티플렉서인 셀렉터(Selector)이다. 셀렉터는 복수 개의 채널 중에서 준비완료된 채널을 선택하는 방법을 제공한다.
Java NIO의 Selectors를 사용하면 단일 스레드가 여러 입력 채널을 모니터링할 수 있습니다. 이 메커니즘을 사용하면 단일 스레드에서 여러 채널을 쉽게 관리할 수 있다.
클라이언트 하나당 쓰레드 하나를 생성해서 처리하기 때문에 쓰레드가 많이 생성될 수록 급격한 성능 저하를 가졌던 단점을 개선하는 Reactor 패턴의 구현체이다.
Java NIO 채널은 다음과 같은 몇 가지 차이점이 있는 스트림과 유사하다.
채널 구현 처리
Scatter/Gather 구현으로 효율 적인 IO 처리 지원
프로세스에서 사용하는 버퍼 목록을 한번의 시스템 콜로 읽고 쓸수 있게 되는 기능
Java NIO 버퍼는 NIO 채널과 상호 작용할 때 사용된다. 데이터는 채널에서 버퍼로 읽고 버퍼에서 채널로 기록된다.
버퍼는 데이터를 쓰고 나중에 다시 읽을 수 있는 메모리 블록이다. 이 메모리 블록은 NIO Buffer 객체로 래핑되어 메모리 블록으로 작업하기 쉽게 만드는 메서드를 제공한다.
Buffer를 사용하여 데이터를 읽고 쓰는 것은 일반적으로 다음과 같은 작은 4단계 프로세스를 따른다.
Java NIO 버퍼의 유형
Java NIO Selector는 하나 이상의 Java NIO 채널 인스턴스를 검사 하고 예를 들어 읽기 또는 쓰기를 위해 준비된 채널을 결정할 수 있는 구성요소이다.
단일 스레드를 사용하여 여러 채널을 모니터 하면서 연결, 이벤트 처리, 관리를 할수 있다.
NIO 서버 데이터 처리 순서
Send
이과정에서 Selector는 단일 스레드로 멀티스레드처럼 처리가 가능하는데 이동작이 multiplexing이라 할 수 있다.
Receive
이때 버퍼(가상 주소)를 사용하여 물리 메모리에 커널 영역의 가상 주소와 매핑시켜 커널 영역에서 유저 영역으로 데이터를 복사하지 않고 바로 참조한다. 즉, I/O 대기 없이 Non-Blocking방식으로 데이터를 처리한다.
https://taes-k.github.io/2021/01/06/java-nio/
https://jeong-pro.tistory.com/145
https://dev-coco.tistory.com/42
http://tutorials.jenkov.com/java-nio/nio-vs-io.html
https://junshock5.tistory.com/149
https://www.slideshare.net/kslisenko/networking-in-java-with-nio-and-netty-76583794