JAVA 비동기 프로그래밍의 전반적인 이해: Runnable에서 CompletableFuture까지

자바 비동기 프로그래밍의 기초

비동기 작업
비동기 작업

 

자바의 비동기 프로그래밍은 애플리케이션의 성능을 향상시키기 위한 필수적인 기술입니다. 초기 단계에서는 ThreadRunnable을 사용한 기본적인 쓰레드 관리로 시작했으며, 시간이 지남에 따라 ExecutorService, Callable, Future, 그리고 CompletableFuture 등 보다 발전된 모델로 진화했습니다. 이 포스팅에서는 이러한 개념들을 자세히 살펴보고, 각각의 사용 방법과 장단점을 탐구해보겠습니다.

 

Thread와 Runnable: 비동기 프로그래밍의 출발점

자바에서 가장 기본적인 비동기 실행 모델은 Thread 클래스를 직접 사용하는 것입니다. Runnable 인터페이스는 실행할 작업을 정의하고, 이를 Thread 객체에 전달하여 실행합니다.

Runnable task = () -> System.out.println("비동기 작업 실행");
Thread thread = new Thread(task);
thread.start();

이 방법은 간단한 비동기 작업에 적합하지만, 작업의 결과를 직접 관리해야 하고, 예외 처리가 복잡해질 수 있습니다.

 

ExecutorService: 쓰레드 풀을 통한 효율적 관리

ExecutorService는 자바의 java.util.concurrent 패키지에 속한 인터페이스로, 쓰레드 풀을 통해 비동기 작업을 효율적으로 관리할 수 있게 합니다. ExecutorService는 execute()와 submit() 두 가지 주요 메소드를 제공합니다.

execute() 메소드

execute() 메소드는 Runnable 객체를 받아 비동기로 실행합니다. 이 메소드는 작업의 결과를 반환하지 않고, 작업 중 발생한 예외를 캐치하지 않기 때문에 예외 처리가 필요한 경우에는 적합하지 않을 수 있습니다. 만약, 실행 중 작업을 중지하기 위해서는 shutdown()을 걸어줘야합니다.

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> System.out.println("execute()를 통한 비동기 작업"));
executor.shutdown();

submit() 메소드

submit() 메소드는 Runnable 또는 Callable 객체를 받아 실행하고, 작업의 결과를 나타내는 Future 객체를 반환합니다. Callable은 Runnable과 달리 결과를 반환하고, 예외를 던질 수 있어 보다 유연한 비동기 작업 처리가 가능합니다.

Future<String> future = executor.submit(() -> {
    Thread.sleep(1000);
    return "submit() 결과";
});

 

CompletableFuture: 비동기 프로그래밍의 고급 추상화

CompletableFuture는 Java 8에서 도입되어, 비동기 작업의 결과를 처리하고, 여러 작업을 조합하며, 완료 시점에 수행할 작업을 지정할 수 있는 고급 추상화를 제공합니다. CompletableFuture는 함수형 프로그래밍 패턴을 활용하여 비동기 로직을 간결하게 표현할 수 있게 해줍니다.

CompletableFuture.supplyAsync(() -> {
    return "CompletableFuture 비동기 작업";
}).thenApply(result -> {
    return result.toUpperCase();
}).thenAccept(System.out::println);

 

결론: 자바 비동기 프로그래밍의 미래

자바의 비동기 프로그래밍은 RunnableThread의 직접적인 사용에서 시작해 ExecutorServiceCompletableFuture 같은 고급 추상화로 발전해왔습니다. 이러한 발전은 개발자가 보다보다 효율적이고 유연한 코드로 비동기 작업을 처리할 수 있게 해주며, 자바 애플리케이션의 성능과 반응성을 크게 향상시키고 있습니다. 최신 자바 버전에서는 CompletableFuture에 더해 리액티브 프로그래밍을 지원하는 Flow API와 같은 새로운 비동기 프로그래밍 모델을 계속해서 도입하고 있습니다. 이러한 도구들을 통해 개발자들은 애플리케이션의 성능을 최적화하고 사용자에게 더 나은 반응성을 제공할 수 있게 되었습니다.