비동기 프로그래밍은 현대 애플리케이션 개발에서 필수적인 기술입니다. 자바에서는 비동기 작업을 효율적으로 처리하기 위해 Callable과 Future라는 인터페이스를 제공합니다. 이 글에서는 비동기의 개념부터 Callable과 Future를 활용한 실질적인 예제까지 차근차근 설명하겠습니다.
비동기란 무엇인가?
비동기 작업이란 작업을 실행한 후 해당 작업이 완료될 때까지 기다리지 않고 다른 작업을 수행할 수 있는 방식을 말합니다. 이는 멀티쓰레드 환경에서 특히 유용하며, 다음과 같은 특징을 갖습니다:
- 병렬 처리: 여러 작업을 동시에 실행하여 처리 속도를 높임.
- 작업 대기 최소화: 작업 완료를 기다리지 않고 다른 작업을 수행 가능.
- 효율성: 시스템 자원을 효율적으로 활용.
자바에서는 이러한 비동기 작업을 구현하기 위해 Runnable, Callable, Future와 같은 도구들을 제공합니다.
Callable과 Future란 무엇인가?
Callable
- Callable은 자바의 인터페이스로, 비동기 작업을 수행하고 결과를 반환할 수 있습니다.
- Runnable과 달리, 작업이 완료된 후 값을 반환하거나 예외를 던질 수 있습니다.
- 주요 메서드
- call() : 작업을 수행하고 결과를 반환합니다.
Future
- Future는 비동기 작업의 결과를 저장하는 컨테이너 역할을 합니다.
- 작업이 완료되기 전까지 결과를 얻으려고 하면 대기 상태가 됩니다.
- 주요 메서드:
- get(): 작업 완료 후 결과를 반환. 작업이 완료되지 않았다면 대기.
- isDone(): 작업 완료 여부를 반환.
- cancel(): 작업을 취소.
Callable과 Runnable의 차이점
특징 | Runnable | Callable |
메서드 | run() | call() |
결과 반환 | 없음 | 있음 |
예외 처리 | 예외 처리 불가능 | 예외 처리 가능 |
사용 목적 | 단순 작업 실행 | 작업 실행 후 결과 반환 및 예외 처리 |
Callable과 Future 사용 방법
Callable과 Future를 사용하려면 ExecutorService를 활용하여 비동기 작업을 실행하고 결과를 관리할 수 있습니다. 아래에서 단계별로 설명하겠습니다.
1. Callable 구현하기
Callable 인터페이스를 구현하여 작업을 정의합니다.
import java.util.concurrent.Callable;
// Callable 구현 클래스
public class SumTask implements Callable<Integer> {
private int a;
private int b;
public SumTask(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public Integer call() throws Exception {
// 두 숫자의 합을 계산하고 반환
return a + b;
}
}
2. ExecutorService를 사용해 Callable 실행하기
ExecutorService를 통해 Callable 작업을 실행하고, 결과를 Future로 관리합니다.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class CallableExample {
public static void main(String[] args) throws Exception {
// ExecutorService 생성 (스레드 풀 크기: 2)
ExecutorService executor = Executors.newFixedThreadPool(2);
// Callable 작업 생성
SumTask task = new SumTask(5, 10);
// Callable 작업 제출하고 Future 객체 반환받음
Future<Integer> future = executor.submit(task);
// 작업 완료 여부 확인
if (!future.isDone()) {
System.out.println("작업 진행 중...");
}
// 작업 결과 가져오기
Integer result = future.get(); // 작업이 완료될 때까지 대기
System.out.println("작업 결과: " + result);
// ExecutorService 종료
executor.shutdown();
}
}
3. 여러 Callable 작업 실행하기
여러 Callable 작업을 동시에 실행하고 결과를 처리하는 방법입니다.
import java.util.concurrent.*;
public class MultiCallableExample {
public static void main(String[] args) throws Exception {
// ExecutorService 생성
ExecutorService executor = Executors.newFixedThreadPool(3);
// 여러 Callable 작업 생성
Callable<Integer> task1 = () -> {
Thread.sleep(1000);
return 10;
};
Callable<Integer> task2 = () -> {
Thread.sleep(2000);
return 20;
};
Callable<Integer> task3 = () -> {
Thread.sleep(3000);
return 30;
};
// 작업 제출
Future<Integer> future1 = executor.submit(task1);
Future<Integer> future2 = executor.submit(task2);
Future<Integer> future3 = executor.submit(task3);
// 결과 가져오기
System.out.println("Task1 결과: " + future1.get());
System.out.println("Task2 결과: " + future2.get());
System.out.println("Task3 결과: " + future3.get());
// ExecutorService 종료
executor.shutdown();
}
}
Callable과 Future 활용 사례
1. 파일 다운로드
여러 파일을 동시에 다운로드하면서 다운로드 완료 후 파일 크기를 반환하는 작업에 활용할 수 있습니다.
2. 데이터베이스 쿼리 처리
비동기적으로 여러 쿼리를 실행하고 결과를 반환받는 데 사용할 수 있습니다.
3. 계산 작업
복잡한 계산 작업을 여러 쓰레드로 나누어 실행한 후 결과를 통합하는 데 적합합니다.
Callable과 Future는 자바에서 비동기 작업을 구현하는 강력한 도구입니다. Runnable보다 더 많은 기능을 제공하며, 작업 결과를 반환하거나 예외를 처리할 수 있습니다. 실무에서 비동기 작업을 효율적으로 처리하려면 Callable과 Future를 잘 활용하는 것이 중요합니다.
'Java' 카테고리의 다른 글
[JAVA] Optional 클래스로 NullPointerException 방지하기 (0) | 2025.04.10 |
---|---|
[Java] Queue 구현 예제 (0) | 2025.04.07 |
[Java] ScheduledExecutorService로 JVM 메모리 사용량 모니터링하기 (0) | 2025.04.02 |
[Java] Stack 구현 예제 (1) | 2025.03.31 |
[JAVA] HttpURLConnection을 활용한 HTTP 통신과 REST API 이해하기 (0) | 2025.03.27 |