728x90

AsynchronousChannel을 지원한다고 한다.

callback 함수를 지정할 수 있고, future로 반환을 지원한다고 한다.

callback과 future를 사용하면 비동기적인 로직이 가능할 것 같다.

 

  • File - callback

우선 callback 함수를 이용해서 파일을 읽어보자.

@Slf4j
public class AsyncFileChannelReadCallbackExample {

    @SneakyThrows
    public static void main(String[] args) {
        log.info("start");
        var file = new File("path");
        var channel = AsynchronousFileChannel.open(file.toPath());
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024);

        channel.read(byteBuffer, 0, null, new CompletionHandler<Integer, Object>() {
            @SneakyThrows
            @Override
            public void completed(Integer result, Object attachment) {
                byteBuffer.flip();
                var resultString = StandardCharsets.UTF_8.decode(byteBuffer);
                log.info("result: {}", resultString);
                channel.close();
            }

            @Override
            public void failed(Throwable exc, Object attachment) {

            }
        });

        while(channel.isOpen()){
            log.info("Reading...");
        }
        log.info("end");
    }
}

 

completed 함수로 callback을 지정해주어, 파일이 모두 읽히면 result: {}로 내용을 출력할 수 있도록 하였다.

파일이 열린동안 메인 쓰레드가 닫히지 않도록 channel.isOpen으로 대기를 걸어주었다.

 

이렇게 callback으로 파일의 내용이 출력된 것을 볼 수 있다.

 

  • File - future
@Slf4j
public class AsyncFileChannelReadFutureExample {
    
    @SneakyThrows
    public static void main(String[] args) {
        log.info("start");
        
        var file = new File("path");
        
        try(var channel = AsynchronousFileChannel.open(file.toPath())){
            var buffer = ByteBuffer.allocateDirect(1024);
            Future<Integer> channelRead = channel.read(buffer, 0);
            while(!channelRead.isDone()){
                log.info("Reading...");
            }
            
            buffer.flip();
            var result = StandardCharsets.UTF_8.decode(buffer);
            log.info("result: {}", result);
        }
        
        log.info("end");
    }
}

 

이제 Future로 받고, 해당 Future가 끝나기를 기다린 후 파일의 내용을 출력하게 되었다.

코드는 깔끔해졌지만, while에서 동기적으로 동작하게 된다.

 

  • socket - callback

이번엔 소켓이다.

accept하는 부분을 비동기적으로 변경하였다.

@Slf4j
public class AsyncServerSocketCallbackExample {

    @SneakyThrows
    public static void main(String[] args) {
        log.info("start");

        var serverSocketChannel = AsynchronousServerSocketChannel.open();
        var address = new InetSocketAddress("localhost", 8080);
        serverSocketChannel.bind(address);

        serverSocketChannel.accept(null, new CompletionHandler<>() {

            @Override
            public void completed(AsynchronousSocketChannel clientSocket, Object attachment) {
                log.info("accepted");
                var requestBuffer = ByteBuffer.allocateDirect(1024);

                clientSocket.read(requestBuffer, null, new CompletionHandler<>() {
                    @SneakyThrows
                    @Override
                    public void completed(Integer result, Object attachment) {
                        requestBuffer.flip();
                        var request = StandardCharsets.UTF_8.decode(requestBuffer);
                        log.info("request: {}", request);

                        var response = "I am server";
                        var responseBuffer = ByteBuffer.wrap(response.getBytes());
                        clientSocket.write(responseBuffer);
                        clientSocket.close();
                        log.info("end");
                    }
                    @Override
                    public void failed(Throwable exc, Object attachment) {

                    }
                });
            }
            @Override
            public void failed(Throwable exc, Object attachment) {

            }
        });
        Thread.sleep(1000000);
        log.info("end");

    }
}

 

Callback이 2개이다.

바깥은 accept하는 부분이고, 안 쪽은 read하는 부분의 callback이다.

 

 

  • socket - Future
@Slf4j
public class AsyncServerSocketFutureExample {

    @SneakyThrows
    public static void main(String[] args) {
        log.info("start");
        var serverSocketChannel = AsynchronousServerSocketChannel.open();
        var address = new InetSocketAddress("localhost", 8080);
        serverSocketChannel.bind(address);

        Future<AsynchronousSocketChannel> clientSocketFuture = serverSocketChannel.accept();
        while(!clientSocketFuture.isDone()){
            Thread.sleep(100);
            log.info("Wainting");
        }
        var clientSocket = clientSocketFuture.get();

        var requestBuffer = ByteBuffer.allocateDirect(1024);
        Future<Integer> channelRead = clientSocket.read(requestBuffer);
        while(!channelRead.isDone()){
            log.info("Reading...");
        }

        requestBuffer.flip();
        var request = StandardCharsets.UTF_8.decode(requestBuffer);
        log.info("request: {}", request);

        var response = "This is server.";
        var responseBuffer = ByteBuffer.wrap(response.getBytes());
        clientSocket.write(responseBuffer);
        clientSocket.close();
        log.info("end client");

    }
}

 

Future로 변경을 해보았다.

File 때와 마찬가지로 while에서 동기적으로 작동하게 되며, 보완이 필요하다고 생각된다.

'백엔드 > 리액티브 프로그래밍' 카테고리의 다른 글

Java Selector  (1) 2024.03.20
Java IO Server 서버를 NIO로 변경  (0) 2024.03.19
Java NIO  (0) 2024.03.18
JAVA IO  (0) 2024.03.18
Mutiny  (0) 2024.03.14

+ Recent posts