8.8 KiB
8.8 KiB
자바의 Runnable, Callable, Future, CompletableFuture에 대한 설명
자바에서 멀티스레드 프로그래밍을 지원하는 주요 인터페이스와 클래스는 Runnable, Callable, Future, 그리고 CompletableFuture입니다. 이들은 작업을 정의하고, 실행하며, 결과를 처리하는 데 사용됩니다. 아래에서 각 클래스와 관련 메서드를 표로 정리하고, 예시를 통해 사용 방법을 설명하겠습니다.
관련 클래스 및 메서드 표
Runnable 인터페이스
| 메서드명 | 반환 타입 | 설명 |
|---|---|---|
run() |
void |
스레드가 실행할 작업을 정의 (추상 메서드) |
Callable<V> 인터페이스
| 메서드명 | 반환 타입 | 설명 |
|---|---|---|
call() |
V |
결과를 반환하며 예외를 던질 수 있는 작업 정의 |
Future<V> 인터페이스
| 메서드명 | 반환 타입 | 설명 |
|---|---|---|
get() |
V |
작업 결과를 반환 (완료될 때까지 대기) |
get(long, TimeUnit) |
V |
지정된 시간 동안 대기 후 결과 반환 |
cancel(boolean) |
boolean |
작업을 취소 시도하고 성공 여부 반환 |
isDone() |
boolean |
작업이 완료되었는지 확인 |
isCancelled() |
boolean |
작업이 취소되었는지 확인 |
CompletableFuture<V> 클래스
| 메서드명 | 반환 타입 | 설명 |
|---|---|---|
runAsync(Runnable) |
CompletableFuture<Void> |
비동기적으로 Runnable 실행 |
supplyAsync(Supplier<V>) |
CompletableFuture<V> |
비동기적으로 값을 제공하는 작업 실행 |
thenApply(Function<T, U>) |
CompletableFuture<U> |
이전 작업의 결과에 함수를 적용하여 변환된 결과 반환 |
thenAccept(Consumer<T>) |
CompletableFuture<Void> |
결과에 대한 소비 동작 수행 |
thenRun(Runnable) |
CompletableFuture<Void> |
결과와 상관없이 후속 작업 실행 |
exceptionally(Function<Throwable, T>) |
CompletableFuture<T> |
예외 발생 시 처리 로직 정의 |
complete(V) |
boolean |
작업을 수동으로 완료하고 결과 설정 |
join() |
V |
작업 완료를 기다리고 결과 반환 (스레드 풀에서 사용 시 주의) |
allOf(CompletableFuture<?>...) |
CompletableFuture<Void> |
여러 CompletableFuture가 모두 완료될 때까지 대기 |
anyOf(CompletableFuture<?>...) |
CompletableFuture<Object> |
여러 CompletableFuture 중 하나가 완료되면 결과 반환 |
설명 및 예시
이들 클래스는 멀티스레드 작업의 정의와 실행, 결과 처리를 다룹니다. Runnable은 기본적인 작업 단위이고, Callable은 결과를 반환하며, Future는 결과를 추적하고, CompletableFuture는 비동기 작업의 조합과 예외 처리를 지원합니다.
1. Runnable: 기본 작업 정의
Runnable은 결과를 반환하지 않는 간단한 작업을 정의합니다.
public class RunnableExample {
public static void main(String[] args) {
Runnable task = () -> {
System.out.println("Runnable 작업 실행: " + Thread.currentThread().getName());
};
Thread thread = new Thread(task);
thread.start();
}
}
- 출력 예시:
Runnable 작업 실행: Thread-0
2. Callable과 Future: 결과 반환
Callable은 값을 반환하며, Future로 결과를 받습니다.
import java.util.concurrent.*;
public class CallableFutureExample {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<String> task = () -> {
Thread.sleep(1000);
return "Callable 작업 완료";
};
Future<String> future = executor.submit(task);
System.out.println("작업 제출 완료");
String result = future.get(); // 완료 대기
System.out.println(result);
executor.shutdown();
}
}
- 출력 예시:
작업 제출 완료 (1초 후) Callable 작업 완료 - 설명:
Future.get()은 작업이 끝날 때까지 대기하며 결과를 반환.
3. CompletableFuture: 비동기 작업 조합
CompletableFuture는 비동기 작업을 연결하고 결과를 처리하는 데 유용합니다.
import java.util.concurrent.*;
public class CompletableFutureExample {
public static void main(String[] args) throws Exception {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "비동기 결과";
}).thenApply(result -> result + " 처리됨")
.thenApply(result -> result.toUpperCase());
String result = future.get();
System.out.println(result);
}
}
- 출력 예시:
(1초 후) 비동기 결과 처리됨 - 설명:
supplyAsync로 값을 생성하고,thenApply로 결과를 변환.
4. CompletableFuture 예외 처리 및 조합
예외 처리와 여러 작업의 동시 실행을 다룹니다.
import java.util.concurrent.*;
public class CompletableFutureAdvancedExample {
public static void main(String[] args) throws Exception {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "작업 1";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("작업 2 실패");
}).exceptionally(throwable -> "복구: " + throwable.getMessage());
CompletableFuture<Void> all = CompletableFuture.allOf(future1, future2);
all.thenRun(() -> {
try {
System.out.println(future1.get() + " & " + future2.get());
} catch (Exception e) {
e.printStackTrace();
}
}).join(); // 모든 작업 완료 대기
}
}
- 출력 예시:
작업 1 & 복구: java.lang.RuntimeException: 작업 2 실패 - 설명:
exceptionally로 예외를 처리하고,allOf로 여러 작업을 조합.
5. CompletableFuture로 수동 완료
complete를 사용해 작업을 수동으로 완료할 수 있습니다.
import java.util.concurrent.*;
public class ManualCompleteExample {
public static void main(String[] args) {
CompletableFuture<String> future = new CompletableFuture<>();
new Thread(() -> {
try {
Thread.sleep(1000);
future.complete("수동 완료");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
String result = future.join();
System.out.println(result);
}
}
- 출력 예시:
(1초 후) 수동 완료
비교와 특징
Runnable: 결과 없음, 단순 작업 실행.Callable: 결과 반환,Future와 함께 사용.Future: 비동기 작업 상태 추적, 블록킹 방식.CompletableFuture: 비동기 작업 조합, 예외 처리, 논블록킹 지원.
결론
Runnable과 Callable은 작업을 정의하고, Future는 결과를 추적하며, CompletableFuture는 복잡한 비동기 작업을 유연하게 처리합니다. 상황에 따라 적합한 클래스를 선택해 사용하면 효율적인 멀티스레드 프로그래밍이 가능합니다. 위 예시를 참고하여 실제 애플리케이션에 적용해 보세요!