Spring Webflux) Java NIO

Date:    Updated:

카테고리:

Java NIO

  • Java New Input/Ouput 이라는 의미
  • Java 1.4 에서 처음으로 도입되었다.
  • Java IO와 마찬가지로 파일과 네트워크에 데이터를 읽고 쓸 수 있는 API를 제공한다.
  • Java IO는 byte 기반이었으나 NIO는 buffer 기반이다.
  • non-blocking을 지원한다.
    • non-blocking을 지원하지 않는 일부 API가 존재한다.
  • selector, channel의 도입으로 높은 성능을 보장한다.

Channel과 Buffer

  • 데이터를 읽을 때
    • 적절한 크기의 Buffer를 생성하고 Channel의 read() 메서드를 사용하여 데이터를 Buffer에 저장한다.
  • 데이터를 쓸 때
    • 먼저 Buffer에 데이터를 저장하고 Channel의 write() 메서드를 사용하여 목적지로 전달한다.
  • Buffer는 clear() 메서드로 초기화 하여 다시 사용 가능하다.

Buffer

Buffer의 종류

  • ByteBuffer (byte 단위로 데이터 read/write)
  • CharBuffer (char)
  • ShortBuffer (short)
  • IntBuffer (int)
  • LongBuffer (long)
  • FloatBuffer (float)
  • DoubleBuffer (double)

Buffer 위치 속성

  • capacity
    • Buffer가 저장할수 있는 데이터의 최대 크기를 뜻한다.
    • Buffer 생성시 결정되며 변경이 불가하다.
    • ex. capacity가 1kb에 해당하는 buffer를 저장하면 1kb 밖에 저장못한다.
  • position
    • Buffer에서 현재 위치를 가리킨다.
    • Buffer에서 데이터를 읽거나 쓸 때, 해당 위치부터 시작한다.
    • Buffer에 1byte가 추가될 때마다 1씩 증가한다.
  • limit
    • Buffer에서 데이터를 읽거나 쓸 수 있는 마지막 위치이다.
    • limit 이후로는 데이터를 읽거나 쓰기가 불가하다.
    • 최초 생성시 capacity와 동일한 값을 가진다.
  • mark
    • 현재 position 위치를 mark()로 지정할 수 있다.
    • reset() 호출 시 position을 mark로 이동한다.
  • 각 속성별 가질수 있는 크기 비교
    • 0 <= mark <= position <= limit() <= capacity

Buffer 위치 초기상태 예시

  • capacity는 초기 주어진 값으로 세팅됨
  • limit은 capacity와 동일
  • position은 0
    • 데이터를 읽거나 쓸때마다 증가하며 limit, capacity를 넘을 수 없다.

flip

  • flip은 Buffer의 limit 위치를 현재 position 위치로 이동시키고 position을 0으로 리셋시킨다.
  • Buffer를 쓰기 모드에서 읽기모드로 전환하는 경우에 사용한다.
    • ex. 파일로부터 buffer를 읽어 들여서 한 문자당 1byte씩 100개의 문자를 읽어들인다.
    • buffer에 작성된 문자를 읽기위해 flip을 사용하여 position을 0으로 초기화하고 마지막으로 작성된 문자열 위치를 limit으로 둔다.

rewind

  • rewind는 Buffer의 position 위치를 0으로 리셋하되, limit은 유지한다.
  • buffer에 있는 내용을 처음부터 다시 읽는 경우에 사용한다.

clear

  • clear는 buffer의 limit 위치를 capacity 위치로 이동시키고, position을 0으로 리셋한다.
  • buffer안의 내용을 초기화 할때 사용한다.

Buffer 예시

try (var fileChannel = FileChannel.open(file.toPath())) {
    var byteBuffer = ByteBuffer.allocateDirect(1024); 
    // buffer 별 position, limit, capacity 로그 출력하는 메서드
    logPosition("allocate", byteBuffer);
    
    // file로부터 값을 읽어서 byteBuffer에 write 
    fileChannel.read(byteBuffer); 
    logPosition("write", byteBuffer);
    
    // flip()을 호출하여 읽기모드로 전환     
    byteBuffer.flip(); 
    logPosition("flip1", byteBuffer);
    
    // 읽기모드로 전환하여 처음부터 limit(마지막까지 write한 위치까지)까지 읽음 
    var result = StandardCharsets.UTF_8.decode(byteBuffer); 
    log.info("result: {}", result);
    logPosition("read1", byteBuffer);

    byteBuffer.rewind(); 
    logPosition("rewind", byteBuffer);

    var result2 = StandardCharsets.UTF_8.decode(byteBuffer); 
    log.info("result2: {}", result2);
    logPosition("read2", byteBuffer);

    var result3 = StandardCharsets.UTF_8.decode(byteBuffer); 
    log.info("result3: {}", result3);
    logPosition("read3", byteBuffer);

    byteBuffer.clear(); 
    logPosition("clear", byteBuffer);
}
21:25 [main] - allocate) position: 0, limit: 1024, capacity: 1024 
21:25 [main] - write) position: 12, limit: 1024, capacity: 1024 
21:25 [main] - flip1) position: 0, limit: 12, capacity: 1024 
21:25 [main] - result: Hello world
21:25 [main] - read1) position: 12, limit: 12, capacity: 1024 
21:25 [main] - rewind) position: 0, limit: 12, capacity: 1024 
21:25 [main] - result2: Hello world
21:25 [main] - read2) position: 12, limit: 12, capacity: 1024 
21:25 [main] - result3:
21:25 [main] - read3) position: 12, limit: 12, capacity: 1024 
21:25 [main] - clear) position: 0, limit: 1024, capacity: 1024

📣 Reference

패스트캠퍼스 - Spring Webflux 완전정복 : 코루틴부터 리액티브 MSA 프로젝트까지

댓글남기기