[java] 자바 NIO(Non-blocking I/O)

자바 NIO(Non-blocking I/O)는 자바에서 I/O 작업을 동시에 처리하는데 사용되는 기술입니다. 이 기술은 기존의 자바 I/O에 비해 효율적으로 리소스를 활용할 수 있고, 멀티쓰레딩을 이용하여 더 많은 연결을 처리할 수 있습니다.

NIO는 java.nio 패키지에 속한 클래스와 인터페이스를 사용하여 구현됩니다.

주요 특징

채널과 버퍼

NIO에서 채널은 데이터의 출입구 역할을 하며, 입력 채널출력 채널이 있습니다. 버퍼는 데이터를 임시로 저장하는 공간으로 채널과 상호작용하여 데이터를 송수신합니다.

아래는 버퍼를 이용한 파일 입출력 예시 코드입니다.

import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.StandardOpenOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.io.IOException;

public class FileIO {
    public static void main(String[] args) {
        Path path = Paths.get("file.txt");
        try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int bytesRead = fileChannel.read(buffer);
            // 버퍼를 사용하여 데이터 처리
            buffer.flip();
            while (buffer.hasRemaining()) {
                System.out.print((char) buffer.get());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

선택기(Selector)

선택기는 다중 채널을 관리하는데 사용됩니다. 하나의 스레드에서 여러 채널의 I/O 이벤트를 모니터링하고, 발생한 이벤트에 따라 작업을 처리할 수 있습니다.

아래는 선택기를 사용한 네트워크 통신 예시 코드입니다.

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class Server {
    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.bind(new InetSocketAddress(8080));
        serverSocket.configureBlocking(false);
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select();
            Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
            while (keys.hasNext()) {
                SelectionKey key = keys.next();
                if (key.isAcceptable()) {
                    // 새로운 연결 처리
                    SocketChannel client = serverSocket.accept();
                    client.configureBlocking(false);
                    client.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    // 데이터 읽기 처리
                    SocketChannel client = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    client.read(buffer);
                    buffer.flip();
                    while (buffer.hasRemaining()) {
                        System.out.print((char) buffer.get());
                    }
                }
                keys.remove();
            }
        }
    }
}

NIO를 이용하면 효율적인 I/O 작업 처리가 가능하고, 적은 리소스로 높은 성능을 얻을 수 있습니다. 다만, 구현이 복잡하고 오류에 민감하다는 점을 주의해야 합니다.

위의 내용은 Oracle 자바 문서를 참고하여 작성되었습니다.