[Java] NIO

kiteB·2022년 5월 9일
0

Java2

목록 보기
30/36
post-thumbnail

[ NIO란?]

자바 4부터 새로운 입출력(NIO: New Input/Output)이라는 뜻에서 java.nio 패키지가 포함되었는데, 자바 7로 버전업하면서 자바 IO와 NIO 사이의 일관성 없는 클래스 설계를 바로 잡고, 비동기 채널 등의 네트워크 지원을 대폭 강화한 NIO.2 API가 추가되었다.

  • NIO.2는 java.nio2 패키지로 제공되지 않고 java.nio의 하위 패키지(java.nio.channels, java.nio.charset, java.nio.file)에 통합되어 있다.
  • 앞으로 NIONIO.2를 구별하지 않고 그냥 NIO로 부르기로 하겠다.

✅ NIO에서 제공하는 패키지

NIO 패키지포함되어 있는 내용
java.nio다양한 버퍼 클래스
java.nio.channels파일 채널, TCP 채널, UDP 채널 등의 클래스
java.nio.channels.spijava.nio.channels 패키지를 위한 서비스 제공자 클래스
java.nio.charset문자셋, 인코더, 디코더 API
java.nio.charset.spijava.nio.charset 패키지를 위한 서비스 제공자 클래스
java.nio.file파일 및 파일 시스템에 접근하기 위한 클래스
java.nio.file.attribute파일 및 파일 시스템의 속성에 접근하기 위한 클래스
java.nio.file.spijava.nio.file 패키지를 위한 서비스 제공자 클래스

[ IO와 NIO의 차이점 ]

IO와 NIO는 데이터를 입출력한다는 목적은 동일하지만, 방식에 있어서 크게 차이가 난다.

구분IONIO
입출력 방식스트림 방식채널 방식
버퍼 방식넌버퍼(non-buffer)버퍼(buffer)
비동기 방식지원 안함지원
블로킹/넌블로킹 방식블로킹 방식만 지원블로킹/넌블로킹 방식 모두 지원

1. 스트림(stream) vs 채널(channel)

IO는 스트림 기반이다.

  • 스트림은 입력 스트림과 출력 스트림으로 구분되어 있다.
    • 데이터를 읽기 위해서는 입력 스트림을 생성해야 하고,
    • 데이터를 출력하기 위해서는 출력 스트림을 생성해야 한다.
  • 예를 들어 하나의 파일에서 데이터를 읽고 저장하는 작업을 모두 해야 한다면 FileInputStreamFileOutputStream을 별도로 생성해야 한다.

NIO는 채널 기반이다.

  • 채널은 스트림과 달리 양방향으로 입력과 출력이 가능하다. 그러므로 입력과 출력을 위한 별도의 채널을 만들 필요가 없다.
  • 예를 들어 하나의 파일에서 데이터를 읽고 저장하는 작업을 모두 해야 한다면 FileChannel 하나만 생성하면 된다.

2. 넌버퍼(non-buffer) vs 버퍼(buffer)

IO는 출력 스트림이 1바이트를 쓰면 입력 스트림이 1바이트를 읽는다.

  • 이런 시스템은 대체로 느리다. 이것보다는 버퍼를 사용해서 복수 개의 바이트를 한꺼번에 입력받고 출력하는 것이 빠른 성능을 낸다.
  • 그래서 IO는 버퍼를 제공해주는 보조 스트림인 BufferedInputStream, BufferedOutputStream을 연결해서 사용하기도 한다.

NIO는 기본적으로 버퍼를 사용해서 입출력을 하기 때문에 IO보다는 입출력 성능이 좋다.

  • 채널은 버퍼에 저장된 데이터를 출력하고, 입력된 데이터를 버퍼에 저장한다.

  • IO는 스트림에서 읽은 데이터를 즉시 처리한다. 그렇기 때문에 스트림으로부터 입력된 전체 데이터를 별도로 처리하지 않으면, 입력된 데이터의 위치를 이동해 가면서 자유롭게 이용할 수 없다.
  • NIO는 읽은 데이터를 무조건 버퍼에 저장하기 때문에 버퍼 내에서 데이터의 위치를 이동해 가면서 필요한 부분만 읽고 쓸 수 있다.

3. 블로킹(blocking) vs 넌블로킹(non-blocking)

IO는 블로킹된다.

  • 입력 스트림의 read() 메소드를 호출하면 데이터가 입력되기 전까지 스레드는 블로킹(대기 상태) 된다.
    마찬가지로 출력 스트림의 write() 메소드를 호출하면 데이터가 출력되기 전까지 스레드는 블로킹된다.
  • IO 스레드가 블로킹되면 다른 일을 할 수 없고 블로킹을 빠져나오기 위해 인터럽트(interrupt)도 할 수 없다. 블로킹을 빠져나오는 유일한 방법은 스트림을 닫는 것이다.

NIO는 블로킹과 넌블로킹 특징을 모두 가지고 있다.

  • IO 블로킹과의 차이점은 NIO 블로킹은 스레드를 인터럽트함으로써 빠져나올 수가 있다는 것이다.
  • 블로킹의 반대 개념이 넌블로킹인데, 입출력 작업 시 스레드가 블로킹되지 않는 것을 말한다.
  • NIO의 넌블로킹은 입출력 작업 준비가 완료된 채널만 선택해서 작업 스레드가 처리하기 때문에 작업 스레드가 블로킹되지 않는다. 여기서 작업 준비가 완료되었다는 것은 지금 바로 읽고 쓸 수 있는 상태를 말한다.
  • NIO 넌블로킹의 핵심 객체는 멀티플렉서(multiplexor)셀렉터(Selector)이다.
    • 셀렉터는 복수 개의 채널 중에서 준비 완료된 채널을 선택하는 방법을 제공해준다.

📌 IO와 NIO 선택

네트워크 프로그램을 개발할 때 IO와 NIO 선택 기준에 대해 생각해보자!

  • NIO는 불특정 다수의 클라이언트 연결 또는 멀티 파일들을 넌블로킹이나 비동기로 처리할 수 있기 때문에 과도한 스레드 생성을 피하고 스레드를 효과적으로 재사용할 수 있다.
  • 또한 운영체제의 버퍼(다이렉트 버퍼)를 이용한 입출력이 가능하기 때문에 입출력 성능이 향상된다.
  • NIO는 연결 클라이언트 수가 많고, 하나의 입출력 처리 작업이 오래 걸리지 않는 경우에 사용하는 것이 좋다.
  • 스레드에서 입출력 처리가 오래 걸린다면 대기하는 작업의 수가 늘어나기 때문에 제한된 스레드로 처리하는 것이 오히려 불리할 수 있다.
  • 대용량 데이터를 처리할 경우에는 IO가 더 유리한데, NIO는 버퍼의 할당 크기도 문제되고, 모든 입출력 작업에 버퍼를 무조건 사용해야 하므로 받은 즉시 처리하는 IO보다는 좀 더 복잡하다. 연결 클라이언트 수가 적고, 전송되는 데이터가 대용량이면서 순차적으로 처리될 필요성이 있을 경우에는 IO로 서버를 구현하는 것이 좋다.

NIO는 연결 클라이언트 수가 많고, 하나의 입출력 처리 작업이 오래 걸리지 않는 경우, IO는 연결 클라이언트 수가 적고, 전송되는 데이터가 대용량이며 순차적으로 처리될 필요성이 있을 경우에 적합하다.


[ 참고자료 ]

이것이 자바다 책

profile
🚧 https://coji.tistory.com/ 🏠

0개의 댓글