Java NIO Overview
Java NIO ( New I/O )는 Java 1.4부터 사용하던 IO API의 대안책(Java IO, Java networking API)이다. Java NIO는 기존의 IO와 다른 방식으로 동작을 제안한다.
1) Java NIO : Non-blocking IO
예를 들면, Thread가 channel 에게 data를 읽어 buffer로 넣도록 요청할 수 있다. channel이 데이터를 읽어 buffer에 넣는 동안, 스레드는 다른 일을 할 수 있다. data를 읽어 buffer에 다 넣으면, 스레드는 이제 작업을 진행하면 된다. channel에 쓰는 것도 똑같은 방식으로 진행된다.
2) Java NIO : Selectors
Java NIO는 Selector라는 개념을 가지고 있다. selector는 connection opened, data arrived등과 같은 이벤트를 위한 채널들을 모니터해주는 객체이다. 즉, 단일 스레드에서 데이터를 위한 채널들을 모니터할 수 있다.
3) Java NIO : Channel과 Buffer
기존 IO API에서는 byte stream과 character stream을 이용했다. NIO API에서는 channel과 buffer를 이용한다. Data는 항상 channel에서 buffer로 읽히고, buffer에서 channle로 쓰여진다.
Java NIO core components
Channels
Buffers
Selectors
Channels과 Buffers
전형적으로, NIO의 모든 IO는 Channel로부터 시작된다.
Java NIO에서 Channel 구현체 :
FileChannel
DatagramChannel
SocketChannel
ServerSocketChannel
- ByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
Selectors
Selector는 단일 스레드에서 여러개의 channel을 다룰 수 있도록 해준다. 만얀 어플리케이션이 많은 connection(Channel)이 열려 있을 때 간편하고, 각자의 connection에는 낮은 traffic을 가진다. 예를 들면, chat server와 같이.
Selector를 쓰기 위해서는 Channel을 등록해야 한다. 그러면 select() method를 호출하면 된다. 이 함수는 등록된 채널 중 하나가 EVENT가 준비될 때 까지 block한다. 이 함수가 return 되면, 그 스레드는 해당 event를 진행한다. Event 종류에는 데이터와 관련된 것이 있다.
Java NIO AsynchronousFileChannel
Java 7에서 AsynchronousFileChannel이 Java NIO에 추가되었다. 해당 클래스는 file 읽고 쓰기를 비동기로 할 수 있게 해준다. 어떻게 사용하는지에 대해 알아보자.
1) AsynchronousFileChannel 만들기
static 함수인 open()으로 채널을 만들자.
Path path = Paths.get("data/test.xml"); AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ);
첫번째는 파일을 가리키는 Path이고, 두번째는 Option에 관련된거 인데, 해당 예제는 file을 읽기용으로만 쓰겠다는 옵션이다.
2) Data 읽기
AsynchronousFileChannel으로 부터 data를 읽는 방법은 2가지가 있다.
- Future 이용
Future<Integer> operation = fileChannel.read(buffer, 0);
첫번째 parameter는 ByteBuffer이다. 해당 Channel로부터 온 데이터는 ByteBuffer로 읽힌다.
두번째 parameter는 읽기 시작할 byte position이다.
read 동작이 완료되지 않더라도 read() 함수는 바로 return 된다. read()함수에서 반환된 Future 객체의 isDone() 함수를 이용하여 read 동작이 언제 완료됐는지 체크 할 수 있다.
read() 함수 사용 예제를 살펴보자.
AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ); ByteBuffer buffer = ByteBuffer.allocate(1024); long position = 0; Future<Integer> operation = fileChannel.read(buffer, position); while(!operation.isDone()); buffer.flip(); byte[] data = new byte[buffer.limit()]; buffer.get(data); System.out.println(new String(data)); buffer.clear();
해당 예제는 CPU를 효과적으로 사용하지는 않았고, 끝날때까지 결국 기다려야 한다.
- CompletionHandler 이용
fileChannel.read(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() { @Override public void completed(Integer result, ByteBuffer attachment) { System.out.println("result = " + result); attachment.flip(); byte[] data = new byte[attachment.limit()]; attachment.get(data); System.out.println(new String(data)); attachment.clear(); } @Override public void failed(Throwable exc, ByteBuffer attachment) { } });
read 동작이 끝나면 CompletionHandler의 completed가 호출된다. result는 몇 바이트가 읽혔는지를 나타낸다.
만약 read 동작이 실패하면 failed()가 호출된다.
http://tutorials.jenkov.com/java-nio/asynchronousfilechannel.html
'Java' 카테고리의 다른 글
디자인 패턴2 - 어댑터 패턴(Adapter Pattern) (0) | 2019.03.04 |
---|---|
디자인 패턴 1 - 파사드 패턴(facade pattern) (0) | 2019.03.03 |
JAVA File I/O에 관하여 (0) | 2017.11.28 |
#java.util.ConcurrentModificationException 이슈 (0) | 2017.10.30 |
Memory leak 문제 해결 (0) | 2017.09.18 |