자바 비동기

박근수·2024년 5월 27일
0

ssafy_PINN

목록 보기
3/4

Java Spring boot에서 비동기가 필요해서 Future를 공부하고 적용한 내용을 정리했음.

Java Future

자바는 1.5부터 Future 인터페이슬 통해 비동기를 제공했다. 초기 Future는 문제가 한계가 있었다. Future 작업 자체는 비동기로 될 지라도 그 결과값을 받아서 처리하기 위해선 get()을 통해 return 값을 활용할 수 있었다. get()이 없다면 return 값을 받을 수가 없었는데 막상 get()을 사용하면 future 작업이 끝날 때까지 기다린다. 따라서 비동기가 아니라 동기가 되는 것이다.

Callable<Integer> task = () -> {
    Thread.sleep(1000);  // 1초동안 대기
    return 123;  // 결과 반환
};

FutureTask<Integer> future = new FutureTask<>(task);
new Thread(future).start();  // Future 작업 실행

// 다른 작업 ...

Integer result = future.get();  // 결과가 준비될 때까지 Blocking
System.out.println("Result: " + result);

이 문제를 해결하기 위해 Java 1.8버전에서 CompletableFuture가 등장했다.

CompletableFuture

CompletableFuture는 비동기 작업 실행, 작업 콜백, Future의 조합 등의 기능을 제공한다. 따라서 여러 비동기 작업을 하나의 흐름으로 만들고 적용할 수 있다.
CompletableFuture를 사용하는 방법은 여러 가지가 있다. 나는 thenCompose와 thenRun을 주로 사용했으나 개발 환경에 따라 적용하는 것이 적절하다.

scheduleProvider.startGame(gameInitVO.getGameId(), currentRound)
               .thenCompose(v -> {
                   // IntStream으로 라운드 수만큼 체인 생성
                   CompletableFuture<Integer> roundChain = CompletableFuture.completedFuture(currentRound);

                   // 각 라운드에 대해 체인에 비동기 작업을 연결
                   for (int round = 1; round <= gameStartRequestDTO.getRoundCount(); round++) {
                       final int currentRoundInLoop = round;
                       roundChain = roundChain.thenCompose(ignored -> scheduleProvider.roundScheduler(gameId, gameStartRequestDTO, currentRoundInLoop));

                   }

                   // 마지막 결과를 `CompletableFuture<Void>`로 변환
                   return scheduleProvider.scheduleFuture(gameId, gameExistLimitTime);
               }).thenRun(() -> {
                   gameService.finishGame(new SocketDTO(gameStartRequestDTO.getSenderNickname(), gameId, gameStartRequestDTO.getSenderTeamId()));

                   log.info("{} Game is dead at {}", gameId, LocalDateTime.now());
                   gameManager.removeGame(gameId);
               }).exceptionally(ex -> {
                   log.error("Error occurred in the CompletableFuture chain: ", ex);
                   throw new BaseException(BaseResponseStatus.OOPS, gameId);
               });

이 외에도 후술할 schedule Future를 사용한 Schedule Executer Service의 schedule을 사용했다. scheduleProvider로 커스텀했다.

CompletableFuture 설명
CompletableFuture를 잘 설명해주신 블로그가 있어서 많이 참고했다.

profile
개성이 확실한편

0개의 댓글