학습
Java 비동기 프로그래밍 (CompletableFuture)
Java 비동기 프로그래밍 (CompletableFuture) — 고급
비동기 프로그래밍 (CompletableFuture)
1. 도입 (왜 배워야 하는가)
비동기 프로그래밍은 현대 소프트웨어 개발에서 필수적입니다. 특히, 웹 애플리케이션이나 대규모 시스템에서는 동시에 여러 작업을 처리해야 하는 경우가 많습니다. Java의 CompletableFuture는 이러한 비동기 작업을 간편하고 효율적으로 처리할 수 있는 강력한 도구입니다.
비동기 프로그래밍을 모르면, 특정 작업이 완료될 때까지 프로그램이 멈춰버리는 동기식 프로그래밍의 단점을 피할 수 없습니다. 예를 들어, 사용자가 웹 페이지를 요청했을 때, 웹 서버가 데이터베이스에서 데이터를 가져오는 동안 페이지가 멈춘다면 사용자 경험이 매우 나빠질 것입니다. 이럴 때 CompletableFuture를 사용하면 비동기적으로 작업을 처리하여 더 나은 성능과 사용자 경험을 제공할 수 있습니다.
2. 핵심 개념 설명
CompletableFuture는 Java의 비동기 프로그래밍을 지원하는 클래스입니다. 이를 통해 비동기 작업을 더 쉽고 직관적으로 구현할 수 있습니다.
- 비동기(Asynchronous): 요청을 보내고 결과를 기다리지 않고 다른 작업을 수행할 수 있는 방식입니다. 예를 들어, 커피를 주문하고 기다리지 않고 친구와 대화하는 것과 같습니다.
- Future: 비동기 작업의 결과를 나타내는 객체로, 작업이 완료될 때까지 기다릴 수 있습니다.
- Completable: 결과가 준비되었을 때 이를 완료할 수 있는 가능성을 의미합니다.
| 용어 | 정의 |
|---|---|
| 비동기 | 요청 후 결과를 기다리지 않고 다른 작업 수행 가능 |
| Future | 비동기 작업의 결과를 나타내는 객체 |
| Completable | 결과가 준비되었을 때 이를 완료할 수 있는 가능성 |
3. 기본 코드 예제
아래 코드는 CompletableFuture의 가장 기본적인 사용법을 보여줍니다.
import java.util.concurrent.CompletableFuture;
public class CompletableFutureExample {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 2초간 작업을 시뮬레이션
try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
return "작업 완료";
});
// 다른 작업을 수행
System.out.println("비동기 작업을 시작했습니다!");
// 결과를 기다림
future.thenAccept(result -> System.out.println(result));
}
}
실행 결과
비동기 작업을 시작했습니다!
작업 완료
코드 한 줄씩 동작 설명
CompletableFuture.supplyAsync(...): 비동기적으로 실행할 작업을 정의합니다. 이 경우, 2초 후에 "작업 완료"라는 문자열을 반환합니다.Thread.sleep(2000): 작업이 완료되는 데 2초 걸린다는 것을 시뮬레이션합니다.System.out.println("비동기 작업을 시작했습니다!");: 비동기 작업이 시작되었음을 알리는 메시지를 출력합니다.future.thenAccept(...): 비동기 작업이 완료되었을 때 실행할 작업을 정의합니다. 결과가 준비되면 "작업 완료"를 출력합니다.4. 실전 활용 예제
예제 1: 쇼핑몰에서 장바구니 업데이트
쇼핑몰 애플리케이션에서 사용자가 장바구니에 상품을 추가하는 경우, 데이터베이스에 상품 정보를 저장하는 작업을 비동기적으로 처리할 수 있습니다.
CompletableFuture<Void> updateCart = CompletableFuture.runAsync(() -> {
// 데이터베이스에 장바구니 업데이트
System.out.println("장바구니 업데이트 중...");
// DB 작업 시뮬레이션
try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("장바구니 업데이트 완료");
});
// 사용자에게 진행 중임을 알림
System.out.println("장바구니에 상품을 추가했습니다.");
updateCart.thenRun(() -> System.out.println("장바구니가 업데이트되었습니다."));
예제 2: 외부 API 호출
비동기적으로 외부 API를 호출하여 데이터를 가져오는 예제입니다.
CompletableFuture<String> fetchData = CompletableFuture.supplyAsync(() -> {
// 외부 API 호출 시뮬레이션
System.out.println("외부 API 호출 중...");
try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
return "API 데이터";
});
fetchData.thenAccept(data -> System.out.println("가져온 데이터: " + data));
5. 흔한 실수와 주의사항
실수 1: 예외 처리 누락
비동기 작업에서 발생하는 예외를 처리하지 않으면 프로그램이 예기치 않게 종료될 수 있습니다.
잘못된 코드
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("예외 발생");
});
올바른 코드
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (true) throw new RuntimeException("예외 발생");
}).exceptionally(ex -> {
System.out.println("예외 처리: " + ex.getMessage());
return "기본값";
});
실수 2: 결과를 기다리지 않음
비동기 작업의 결과를 처리하기 전에 메인 스레드가 종료되면 결과를 볼 수 없습니다.
잘못된 코드
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "작업 완료");
올바른 코드
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "작업 완료");
future.thenAccept(result -> System.out.println(result));
future.join(); // 메인 스레드가 결과를 기다리도록 추가
6. 정리
CompletableFuture를 사용하면 복잡한 비동기 작업을 간편하게 처리할 수 있습니다.다음에 학습하면 좋은 주제: