Future와 오류 처리
시간 제한과 함께 Future.get을 사용하고 ExecutionException을 처리하며 실행 중인 작업을 취소합니다.
Future와 오류 처리은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
Future란 무엇인가
Future<V>는 비동기 계산에서 아직 완료되지 않은 결과를 나타냅니다. 완료 여부 확인, 결과 대기, 오류 처리를 위한 메서드를 제공합니다.
import java.util.concurrent.*;
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Integer> future = pool.submit(() -> {
Thread.sleep(1000);
return 42;
});
System.out.println("Is done? " + future.isDone()); // false
Integer result = future.get(); // blocks
System.out.println("Result: " + result); // 42
pool.shutdown();시간 제한이 있는 future.get()
무기한 멈추는 것을 방지하려면 항상 시간 제한이 있는 형식을 우선 사용합니다.
try {
Integer result = future.get(5, TimeUnit.SECONDS);
System.out.println(result);
} catch (TimeoutException e) {
System.out.println("Timed out");
future.cancel(true); // interrupt the task
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
System.out.println("Task threw: " + e.getCause());
}ExecutionException
작업에서 예외가 발생하면 future.get()은 해당 예외를 ExecutionException으로 감쌉니다. getCause()로 원인을 꺼냅니다.
Future<String> failing = pool.submit(() -> {
throw new IllegalArgumentException("bad input");
});
try {
failing.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
System.out.println(cause.getClass().getSimpleName()); // IllegalArgumentException
System.out.println(cause.getMessage()); // bad input
}Future 취소
cancel(mayInterruptIfRunning)은 작업을 취소하려고 시도합니다. 성공하면 true를 반환합니다. mayInterruptIfRunning이 true이면 실행 중인 스레드에 인터럽트가 전송됩니다.
Future<String> f = pool.submit(() -> {
try {
Thread.sleep(10_000); // long task
return "done";
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return "interrupted";
}
});
boolean cancelled = f.cancel(true); // send interrupt
System.out.println("Cancelled: " + cancelled); // true
System.out.println("Is cancelled: " + f.isCancelled()); // trueisCancelled와 isDone 비교
isDone()은 작업이 정상적으로 완료되었거나, 예외가 발생했거나, 취소된 경우 true를 반환합니다. isCancelled()은 취소된 경우에만 true를 반환합니다.
// After cancel:
System.out.println(f.isDone()); // true
System.out.println(f.isCancelled()); // true
// After normal completion:
Future<Integer> done = pool.submit(() -> 5);
done.get(); // wait
System.out.println(done.isDone()); // true
System.out.println(done.isCancelled()); // false사용 가능한 첫 결과를 위한 CompletionService
ExecutorCompletionService는 풀을 감싸고 다음으로 완료된 Future를 가져오는 take() 메서드를 제공합니다. 제출 순서가 아니라 완료 순서로 가져옵니다.
ExecutorCompletionService<Integer> cs =
new ExecutorCompletionService<>(pool);
for (int i = 0; i < 5; i++) {
final int delay = 5 - i; // submit fastest last
cs.submit(() -> { Thread.sleep(delay * 100); return delay; });
}
for (int i = 0; i < 5; i++) {
Future<Integer> f = cs.take(); // next completed
System.out.println(f.get());
}여러 Future의 안전한 처리
많은 Future에서 결과를 수집할 때는 각 Future를 순회하면서 개별적으로 예외를 처리합니다.
List<Future<String>> futures = new ArrayList<>();
for (int i = 0; i < 5; i++) {
final int id = i;
futures.add(pool.submit(() ->
id % 2 == 0 ? "ok_" + id : (() -> { throw new RuntimeException("fail_"+id); }).get()
));
}
for (Future<String> f : futures) {
try {
System.out.println(f.get());
} catch (ExecutionException e) {
System.out.println("Error: " + e.getCause().getMessage());
}
}풀 종료 후 Future.get()
shutdown() 후에 작업을 제출하면 RejectedExecutionException이 발생합니다. 하지만 종료 전에 제출한 Future는 종료 후에도 가져올 수 있습니다.
ExecutorService pool2 = Executors.newFixedThreadPool(2);
Future<Integer> f = pool2.submit(() -> 99);
pool2.shutdown(); // no new tasks
// Still valid — task was submitted before shutdown:
System.out.println(f.get()); // 99
try {
pool2.submit(() -> 0); // throws!
} catch (RejectedExecutionException e) {
System.out.println("Pool shut down");
}FutureTask: 수동 비동기 결과
FutureTask<V>는 Runnable과 Future<V>를 모두 구현합니다. ExecutorService 없이 Future가 필요할 때 유용합니다.
FutureTask<String> task = new FutureTask<>(() -> "computed");
new Thread(task).start(); // run in any thread
System.out.println(task.get()); // computedFuture를 사용한 재시도 패턴
future.get() 주위에 간단한 재시도 로직을 구현합니다.
Future<String> future = pool.submit(() -> {
if (Math.random() < 0.7) throw new RuntimeException("transient error");
return "success";
});
for (int attempt = 0; attempt < 3; attempt++) {
try {
System.out.println(future.get());
break;
} catch (ExecutionException e) {
System.out.println("Attempt " + (attempt+1) + " failed");
if (attempt == 2) throw e;
future = pool.submit(() -> "retry"); // resubmit
}
}Future의 제한 사항
java.util.concurrent.Future에는 다음과 같은 제한 사항이 있습니다.
- 콜백이 없으므로 get()에서 블로킹해야 합니다.
- 변환을 연결할 수 없습니다.
- 여러 Future를 결합할 수 없습니다.
반응형 비차단 조합이 필요하다면 다음 과정에서 다루는 CompletableFuture를 사용합니다.
확인 문제
작업에서 예외가 발생했습니다. future.get()을 호출하면 어떤 예외가 발생합니까?
복습: Future와 오류 처리
핵심 내용은 다음과 같습니다.
- future.get()은 블로킹되므로 항상 시간 제한이 있는 형식을 사용합니다.
- ExecutionException은 작업의 예외를 감싸며, getCause()로 원인을 꺼냅니다.
- cancel(true)은 인터럽트를 전송하고, isDone/isCancelled로 상태를 확인합니다.
- ExecutorCompletionService.take()은 완료 순서대로 Future를 가져옵니다.
- FutureTask는 Runnable과 Future를 모두 구현합니다.
자주 묻는 질문
“Future와 오류 처리” 강의는 무료인가요?
네 — “Future와 오류 처리” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“Future와 오류 처리”에서 뭘 배우나요?
시간 제한과 함께 Future.get을 사용하고 ExecutionException을 처리하며 실행 중인 작업을 취소합니다. 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Java Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“Future와 오류 처리” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.