멀티스레드와 자바 비동기 작업으로 간단한 콘솔 기반 카페 만들기
 

GitHub - pbg0205/asyc-cafe

Contribute to pbg0205/asyc-cafe development by creating an account on GitHub.

github.com

 

콘솔 화면

 

CompletableFuture?

 자바는 ThreadPool 과 CompletableFuture 를 기반해 비동기 작업을 지원한다. 기본적으로 자바는 Synchrous & Blocking 기반으로 동작하지만 비순차적 작업과 실행 흐름 대기로 인한 자원의 낭비와 작업이 지연될 수 있는 단점이 있다. 이를 개선하기 위한 방법으로 자바에서 또한 비동기(Asynchronous) 지원을 위한 CompletableFuture 와 같은 개념이 대두되었다.

 

Java8 에서 부터 도입된 CompletableFuture 되었다. 기존의 Future 와 비교했을 때 병렬 처리, Callback 지원, 조합 및 체인, 예외 처리, 재사용적인 측면에서 비동기 및 병렬 작업에서의 제어, 조작 측면에서의 이점이 있어 비동기 사용에 있어서는 CompletableFuture 를 권장하고 있다.

 

카페 예제

간단한 기능은 아래와 같다.

  1. 주문은 각 음료의 종류와 수량을 통해 입력한다. (1:2 - 1번 음료, 2잔 주문)
  2. 음료는 각각의 제조하기 위한 일정 시간이 필요하다.
  3. 바리스타는 2명으로 각각 하나의 음료를 제조한다.

 

동기 기반의 음료 제작

Cashier 가 콘솔 입력을 받고 Manager 가 Barista 에게 상세 주문 내역을 전달해 Barista 가 동기적으로 처리하는 경우에는 Barista 가 음료 제작 중에는 Barista 작업이 스레드를 점유하고 있어 Barista 작업이 완료될 때까지 Cashier 가 주문을 입력을 받을 수 없다. 그러므로 주문이 많은 경우 음료가 완료될 때까지 대기할 수 없다.

 

비동기 기반의 음료 제작

 하지만 CompletableFuture 를 활용하면 이 문제를 해결할 수 있다. CompletableFuture 는 ThreadPool 기반의 비동기 작업 지원을 제공한다. 이를 통해 Cashier의 입력 작업을 비동기 처리하고 Barista 의 음료 제조 작업을 병렬적으로 처리할 수 있는 장점이 존재한다.

 

CompletableFuture 코드

CompletableFuture 는 ThreadPool 을 명시하지 않아도 ForkJoinPool 의 병렬성을 파악해 이에 맞는 기본 ThreadPool 을 제공한다.

 

 

ThreadFactory 를 통한 바리스타 이름 설정과 ThreadPool 스레드 갯수 설정을 위해 커스텀으로 설정했다. 

CompletableFuture ThreadPool Custom 설정
Thread 이름 설정을 위한 ThreadFactory 설정

 

 

후기

아쉬운 점

현재 프로젝트에서는 주문 이벤트 구독을 busy waiting  방식으로 이벤트를 풀링하는 방식으로 구현되어 있다. 실시간으로 데이터를 구독하기 위해서는 푸시 기반의 이벤트 스트리밍을 하는 것이 적합하지만 현재 실력에서는 구현하지 못했다. RxJava 나 Reactor 와 같은 라이브러리를 활용하는 방법도 좋은 선택지일 것 같다.

 

비동기를  선호하는 이유

이전 자바 진영에서는 Synchronous & Blocking 의 기반으로 인한 불편함이 많았다. 자바의 대표적인 프레임워크인 Spring 은  동기 기반으로 동작하는 RestTemplate 을 @Async 를 활용해 비동기로 작동하거나 비동기 기반의 Webclient 를 사용했다. 또한 React 라는 자바 비동기 라이브러리를 기반으로 한 Spring Webflux 와 같은 기술이 각광받는 이유 또한 효율적인 리소스 활용에 있어서 장점이 있기 때문인 것 같다.

 

Event-Driven 을 선호하는 이유

카페 예제와 같이 Queue 를 사용해 이벤트 기반으로 메세지를 발행, 구독하도록 설정했다. 비록 예제에서는 하나의 애플리케이션에서 동작하지만 실제 서비스와 같은 큰 규모의 아키텍처에서는 발행자/구독자 사이의 서버 간 성능에 관한 커플링을 줄이고 유연한 시스템을 제공하는데 있어 이점이 있다고 생각한다.

'java > summary' 카테고리의 다른 글

SerialVersionUID를 선언해야 하는 이유  (1) 2024.11.28
Virtual Thread 무엇일까? summary  (0) 2024.11.28
어댑터 패턴(adapter pattern)  (1) 2024.07.09
퍼사드 패턴(Facade Pattern)  (0) 2024.07.08
커맨드 패턴(command pattern)  (0) 2024.07.08